你不知道的JS(下):深入JS(下)
本文是《你不知道的JavaScript(下卷)》的阅读笔记,第三部分:深入JS(下)。 供自己以后查漏补缺,也欢迎同道朋友交流学习。
原文地址
严格模式 (Strict Mode)
ES5 引入了严格模式,通过 "use strict"; 开启。它可以使代码更安全、更易于引擎优化。
- 不允许省略
var的隐式自动全局变量声明。 - 限制了某些不安全或不合理的语法行为。
函数进阶
作为值的函数
函数在 JavaScript 中是第一类对象,可以作为值赋给变量,也可以作为参数传递或从其他函数返回。
javascript
var foo = function() { /* .. */ };
var x = function bar(){ /* .. */ };
立即调用函数表达式 (IIFE)
IIFE 用于创建一个临时作用域并立即执行代码。它也可以有返回值:
javascript
var x = (function IIFE(){
return 42;
})();
x; // 42
闭包 (Closure)
闭包允许函数在其定义的词法作用域之外执行时,仍能"记忆"并访问该作用域。
模块模式
这是闭包最常见的应用。模块允许定义外部不可见的私有实现,同时提供公开 API。
javascript
function User(){
var username, password;
function doLogin(user,pw) {
username = user;
password = pw;
}
var publicAPI = {
login: doLogin
};
return publicAPI;
}
var fred = User();
fred.login( "fred", "12Battery34!" );
this 标识符
this 指向哪个对象取决于函数是如何被调用的。遵循以下四条规则:
- 默认绑定 :非严格模式下指向全局对象,严格模式下为
undefined。 - 隐式绑定 :由上下文对象调用(如
obj1.foo()),指向该对象。 - 显式绑定 :通过
call、apply或bind指定指向。 new绑定:指向新创建的空对象。
javascript
function foo() { console.log( this.bar ); }
var bar = "global";
var obj1 = { bar: "obj1", foo: foo };
var obj2 = { bar: "obj2" };
foo(); // "global" (默认绑定)
obj1.foo(); // "obj1" (隐式绑定)
foo.call( obj2 ); // "obj2" (显式绑定)
new foo(); // undefined (new 绑定)
原型 (Prototype)
当访问对象不存在的属性时,JavaScript 会自动在内部原型链上查找。这是一种属性查找的备用机制(也称为委托)。
javascript
var foo = { a: 42 };
var bar = Object.create( foo );
bar.a; // 42 (委托给 foo 查找)
ES6 核心特性
符号 (Symbol)
Symbol 是 ES6 引入的新原生类型,没有字面量形式,主要用于创建唯一的、不会冲突的键值。
- 单例模式:非常适合实现模块单例。
- 符号注册 :通过
Symbol.for(..)在全局注册表中查找或创建符号。 - 隐藏属性 :符号属性不会出现在一般的属性枚举中(如
Object.keys),需使用Object.getOwnPropertySymbols(..)获取。
迭代器 (Iterator)
迭代器是一个结构化模式,用于从数据源一次提取一个值。
-
接口 :必须包含
next()方法,返回{ value, done }。 -
自定义迭代器 :可以手动实现
[Symbol.iterator]接口。javascriptvar Fib = { [Symbol.iterator]() { var n1 = 1, n2 = 1; return { next() { var current = n2; n2 = n1; n1 = n1 + current; return { value: current, done: false }; } }; } };
生成器 (Generator)
生成器是一种特殊的函数,可以在执行中暂停(yield)并恢复。
- 语法 :
function *foo() { .. }。 - 迭代器控制 :生成器返回一个迭代器,通过调用
next()来控制生成器的执行流。 - 双向通信 :
yield不仅可以返回值,还可以接收next(val)传入的值。
模块 (Modules)
ES6 模块是基于文件的单例,具有静态 API。
- 导出与导入 :使用
export和import。 - 静态加载:编译时确定依赖关系,支持模块间循环依赖。
- 对比旧方法:不再需要依赖闭包和封装函数来实现模块化。
填补与转换 (Polyfilling & Transpiling)
Polyfilling
根据新特性定义,在旧环境中手动实现等价行为的代码。适用于新 API。
javascript
if (!Number.isNaN) {
Number.isNaN = function isNaN(x) {
return x !== x; // NaN 是唯一不等于自身的值
};
}
Transpiling
通过工具(如 Babel)将新语法转换为等价的旧版代码。适用于新语法特性(如箭头函数、解构等),因为这些无法通过 Polyfill 实现。
小结
JavaScript 的进阶特性赋予了这门语言强大的表达能力:
- 闭包与模块:通过词法作用域记忆功能实现私有化封装,是构建大型应用的基础。
this与原型:理解动态绑定规则与原型委托机制,能够更高效地进行对象间的功能复用。- ES6 新范式:迭代器、生成器和原生模块系统标志着 JS 向更成熟、更工程化的方向迈进。
- 兼容性保障:通过 Polyfill 和 Transpiling,我们可以在拥抱未来的同时,确保代码在旧环境中的稳健运行。
掌握这些核心机制,不仅能帮助我们写出更好的代码,更能让我们深入理解 JavaScript 的运行本质。