ECMAScript(ES) 是 JavaScript 的“语法标准说明书”
// ES6 规定箭头函数语法
const sum = (a, b) => a + b;
// ES6 规定 class 语法
class Person {
constructor(name) {
this.name = name;
}
}JavaScript 是基于 ECMAScript 的“具体实现”:
// 浏览器环境下独有的 DOM API(非 ES 标准)
document.querySelector("#btn").addEventListener("click", () => {
alert("按钮被点击");
});// Node.js 环境下独有的文件操作 API(非 ES 标准)
const fs = require("fs");
fs.readFile("data.txt", "utf8", (err, data) => {
console.log(data);
});
动态类型:变量类型在运行时自动推断,无需显式声明:
let a = 10; // number
a = "hello"; // string(类型可动态改变)单线程与事件循环
弱类型与隐式转换: 不同类型变量可进行运算(可能导致意外结果)
console.log(1 + "2"); // "12"(数字转为字符串)
console.log("3" - 1); // 2 (字符串转为数字)从 2015 年开始 tc39委员会决定每年发布新的 ECMAScript 版本
下面是 ES6 兼容性状况,你也可以在 https://caniuse.com/网站查看。

浏览器:本套课程会讲到新的 JS 知识,所以请使用chrome 或 firefox 浏览器来进行学习。
编辑器:推荐使用 vscode 编辑器开始学习,你可能需要安装一些插件才可以高效使用。
浏览器内置了处理的 JS 的解析器,但不同浏览器的性能不同,所以 JS 一般都在浏览器中执行,当然也有可以在服务器后台执行的 JS 解析器。
JS 请求处理步骤如下:

像 style 标签一样,可以在 html 文档中使用 script 标签嵌入 javascript 代码。
<script>
alert('你好,世界!');
</script><script src="tool.js"></script><head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>重学js</title>
</head>
<body>
<h1>重学</h1>
<script src="tool.js"></script>
</body>let price = 100; // 定义商品价格
// let discount = 0.8; (临时禁用这行代码)/*
函数:计算总价
参数:
- price: 单价
- count: 数量
返回:总价(含税)
*/
function calcTotal(price, count) {
return price * count * 1.1;
}/**
* 计算两个数字的和
* @param {number} a - 第一个数字
* @param {number} b - 第二个数字
* @returns {number} 两数之和
* @example
* add(2, 3); // 返回 5
*/
function add(a, b) {
return a + b;
}
以下是 JavaScript 命名规则的详细说明,遵循行业通用规范以提高代码可读性和协作效率:
let name = "重学js";
let Name = "重学js"; // 与 name 不同// 错误示例
let a = 10;
// 正确示例
let maxRetryCount = 10;// 错误
let class = "web";
// 正确
let className = "web";let _count = 1; // 允许
let $price = 100; // 允许
let 2ndPlace = "no"; // 错误let userName = "重学js";
function getUserInfo() {}class UserAccount {}
function DatabaseConnection() {}const MAX_WIDTH = 1920;
const API_BASE_URL = "https://api.mtsws.cn";class User {
constructor() {
this._internalId = 100; // 暗示私有属性
}
}let isLogged = false;
let hasPermission = true;
let canEdit = true;function onClickSubmit() {}
function handleKeyPress() {}以下是关于 JavaScript 变量声明的详细说明,涵盖声明方式、作用域、提升及最佳实践:
var(传统方式)
function example() {
console.log(a); // undefined(变量提升)
var a = 10;
var a = 20; // 允许重复声明
}let(ES6 引入)
if (true) {
// console.log(b); // 报错(TDZ)
let b = 20;
// let b = 30; // 报错(重复声明)
}
// console.log(b); // 报错(超出作用域)const(ES6 引入)
const PI = 3.14;
// PI = 3.1415; // 报错(禁止重新赋值)
const user = { name: "重学js" };
user.name = "你好,世界!"; // 允许修改属性作用域对比

变量提升(Hoisting)
console.log(x); // undefined(声明提升,赋值不提升)
var x = 10;console.log(y); // 报错(ReferenceError)
let y = 20;暂时性死区(TDZ)
function test() {
// TDZ 开始
console.log(tmp); // 报错
// TDZ 结束
let tmp = 100; // TDZ 结束
}全局变量挂载
var globalVar = "重学js";
console.log(window.globalVar); // "重学js"let globalLet = "重学js";
console.log(window.globalLet); // undefined常见错误示例
// 错误1:重复声明
let a = 1;
let a = 2; // SyntaxError
// 错误2:未初始化 const
const URL; // SyntaxError
// 错误3:块级作用域误用
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i)); // 输出 3, 3, 3
}
// 修复:改用 let
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i)); // 输出 0, 1, 2
}弱类型的定义
弱类型的具体表现
1.字符串拼接优先:遇到 +运算符时,若一方为字符串,则转为字符串拼接。
console.log(1 + "2"); // "12"(数字转字符串)
console.log("3" - 1); // 2 (字符串转数字)2.比较时的转换
console.log(1 == "1"); // true(字符串转数字后比较)
console.log(1 === "1"); // false(严格比较类型和值)3.Truthy/Falsy 值:非布尔值在条件判断中自动转为布尔值。
if ("") console.log("不执行"); // Falsy
if ("hello") console.log("执行"); // Truthy常见隐式转换表

弱类型引发的问题
// 示例1:数字与字符串相加
const total = 100 + "50"; // "10050"(预期 150)
// 示例2:数组与数字比较
console.log([] == 0); // true([] 转数字为 0)调试困难- 类型错误可能被隐式转换掩盖,导致问题后期暴露。
function sum(a, b) {
return a + b; // 若传入字符串参数,结果错误
}
sum(10, "20"); // "1020"const input = "100";
const num = Number(input); // 显式转为数字function add(a: number, b: number): number {
return a + b;
}
add(10, "20"); // 编译时报错
function add(a: number, b: number): number {
return a + b;
}
add(10, "20"); // 编译时报错总结
Object.freeze 的作用: 冻结一个对象,使其1.不可修改; 2.不可添加新属性; 3.不可删除现有属性;4.不可修改属性的值;5.不可修改属性的描述符(如 writable、configurable)。
Object.freeze(targetObject);const user = { name: "重学js", age: 10 };
Object.freeze(user);
// 修改属性(静默失败,严格模式报错)
user.name = "Mr 焦";
console.log(user.name); // "重学js"
// 添加属性(失败)
user.email = "admin@qq.com";
console.log(user.email); // undefined
// 删除属性(失败)
delete user.age;
console.log(user.age); // 10console.log(Object.isFrozen(user)); // trueconst data = { config: { theme: "dark" } };
Object.freeze(data);
data.config.theme = "light"; // 修改成功(内部对象未冻结)
console.log(data.config.theme); // "light"严格模式报错-在严格模式下,修改冻结对象属性会抛出 TypeError
。"use strict";
const obj = Object.freeze({ key: 1 });
obj.key = 2; // TypeError: Cannot assign to read only property 'key'const APP_CONFIG = Object.freeze({
API_URL: "https://api.mtsws.com",
MAX_RETRY: 3,
});防止状态篡改
// 共享状态对象
const state = Object.freeze({ loggedIn: false });
// 恶意代码无法意外修改
function deepFreeze(obj) {
Object.freeze(obj);
for (const key in obj) {
if (typeof obj[key] === "object" && !Object.isFrozen(obj[key])) {
deepFreeze(obj[key]);
}
}
return obj;
}
const data = deepFreeze({ user: { name: "重学js" } });
data.user.name = "baidu"; // 修改失败(严格模式报错)1.传值(Pass by Value):传递变量的 副本值,修改副本不影响原变量
适用类型:基本数据类型(number, string, boolean, null, undefined, symbol)
传值场景(基本类型):
let a = 10;
let b = a; // 将 a 的值拷贝给 b
b = 20; // 修改 b 不影响 a
console.log(a); // 10(原值不变)
console.log(b); // 20函数中-传递基本类型(传值)
function updateValue(value) {
value = 100; // 修改形参不影响实参
}
let num = 10;
updateValue(num);
console.log(num); // 10(原值未变)2.传址(Pass by Reference):传递变量的 内存地址引用,修改引用会影响原变量
适用类型:引用数据类型(object, array, function)
传址场景(引用类型)
let obj1 = { name: "重学js" };
let obj2 = obj1; // 将 obj1 的内存地址引用赋值给 obj2
obj2.name = "baidu.com"; // 修改 obj2 会影响 obj1
console.log(obj1.name); // "baidu.com"(原对象被修改)
console.log(obj2.name); // "baidu.com"函数中-传递引用类型(传址)
function updateUser(user) {
user.age = 20; // 修改引用对象的属性会影响原对象
}
const user = { name: "重学js" };
updateUser(user);
console.log(user); // { name: "重学js", age: 20 }(原对象被修改)3.特殊场景分析
let arr1 = [1, 2];
let arr2 = arr1;
arr2 = [3, 4]; // 让 arr2 指向新地址,不再关联 arr1
console.log(arr1); // [1, 2](原数组未变)
console.log(arr2); // [3, 4]const source = { a: 1, b: { c: 2 } };
const copy = { ...source }; // 浅拷贝(只复制第一层属性)
copy.a = 10; // 不影响原对象
copy.b.c = 20; // 修改嵌套对象会影响原对象
console.log(source); // { a: 1, b: { c: 20 } }4.如何避免引用传递的副作用
// 方法1:JSON 序列化(不适用函数、Symbol 等特殊类型)
const obj = { a: 1, b: { c: 2 } };
const deepCopy = JSON.parse(JSON.stringify(obj));
// 方法2:递归拷贝(完整深拷贝)
function cloneDeep(target) {
if (typeof target !== "object" || target === null) return target;
const copy = Array.isArray(target) ? [] : {};
for (const key in target) {
copy[key] = cloneDeep(target[key]);
}
return copy;
}const config = Object.freeze({ theme: "dark" });
function tryModify(cfg) {
cfg.theme = "light"; // 严格模式报错,非严格模式静默失败
}
tryModify(config);5.总结与对比表

1.核心定义

2.何时用 undefined
3.何时用 null
4.总结

