简介
《this & Object Prototypes》深入讲解 JavaScript 最让人困惑的 this 关键字和原型系统。
this 的四种绑定规则
1. 默认绑定
function foo() {
console.log(this.a);
}
var a = 2;
foo(); // 2 - this 指向全局对象 (非严格模式)
// 严格模式下 this 是 undefined
2. 隐式绑定
function foo() {
console.log(this.a);
}
const obj = {
a: 2,
foo: foo
};
obj.foo(); // 2 - this 指向 obj
隐式丢失:
const obj = {
a: 2,
foo: foo
};
const bar = obj.foo; // 引用传递
var a = "global";
bar(); // "global" - 丢失 obj 绑定
3. 显式绑定
function foo() {
console.log(this.a);
}
const obj = { a: 2 };
// call - 立即调用
foo.call(obj); // 2
// apply - 立即调用(参数是数组)
foo.apply(obj, [1, 2]);
// bind - 返回新函数(永久绑定)
const boundFoo = foo.bind(obj);
boundFoo(); // 2
4. new 绑定
function Foo(a) {
this.a = a;
}
const foo = new Foo(2);
console.log(foo.a); // 2 - this 指向新创建的对象
绑定优先级
new 绑定 > 显式绑定 > 隐式绑定 > 默认绑定
function foo(something) {
this.a = something;
}
const obj1 = {};
const obj2 = {};
foo.call(obj1, "obj1");
foo.call(obj2, "obj2");
console.log(obj1.a); // "obj1"
console.log(obj2.a); // "obj2"
// bind 优先级高于 call
const boundFoo = foo.bind(obj1);
boundFoo("bound");
console.log(obj1.a); // "bound"
箭头函数的 this
箭头函数不绑定自己的 this,继承外层作用域的 this:
function foo() {
// 返回箭头函数
return (a) => {
console.log(this.a);
};
}
const obj1 = { a: "obj1" };
const obj2 = { a: "obj2" };
const bar = foo.call(obj1);
bar.call(obj2); // "obj1" - this 永远指向 obj1
原型链
什么是原型?
每个 JavaScript 对象都有一个原型对象(prototype),对象可以从原型继承属性。
const obj = { a: 1 };
console.log(obj.__proto__ === Object.prototype); // true
原型链查找
const grandparent = { a: 1 };
const parent = { b: 2 };
const child = { c: 3 };
// 设置原型
Object.setPrototypeOf(child, parent);
Object.setPrototypeOf(parent, grandparent);
console.log(child.a); // 1 - 沿着原型链查找
console.log(child.b); // 2
console.log(child.c); // 3
原型方法
const obj = { a: 1 };
// hasOwnProperty - 检查自身属性
obj.hasOwnProperty("a"); // true
obj.hasOwnProperty("toString"); // false
// in 操作符 - 检查自身和原型链
"a" in obj; // true
"toString" in obj; // true
对象创建
1. 对象字面量
const obj = { a: 1 };
2. 构造函数
function Foo(name) {
this.name = name;
}
Foo.prototype.sayHi = function() {
console.log("Hi, " + this.name);
};
const foo = new Foo("Lily");
foo.sayHi(); // "Hi, Lily"
3. Object.create()
const parent = { a: 1 };
const child = Object.create(parent);
console.log(child.a); // 1 - 继承 parent
4. ES6 class
class Foo {
constructor(name) {
this.name = name;
}
sayHi() {
console.log("Hi, " + this.name);
}
}
const foo = new Foo("Lily");
foo.sayHi();
小结
- ✅ 理解 this 的四种绑定规则
- ✅ 掌握 call/apply/bind 的用法
- ✅ 理解原型链的工作机制
- ✅ 熟悉 ES6 class 的语法糖本质
- ✅ 能够实现继承和原型链
相关阅读: