1、关于 this 的误解
- this 指向
函数自身
。以下代码试图用 this 指向函数自身的属性来记录调用次数,然而这行不通:
function foo(num) {
console.log("foo: " + num);
this.count++;
}
foo.count = 0;
for (let i = 0; i < 10; i++) {
foo(i);
}
console.log(foo.count);
- this 指向函数的作用域。以下代码试图跨越边界,用 this 引用函数的词法作用域,但会抛出 TypeError:
function foo() {
var a = 2;
this.bar();
}
function bar() {
console.log(this.a);
}
foo();
2、this 的调用位置
调用位置就是函数在代码中被调用的位置。要分析 this 的引用到底是什么关心的是调用位置就在当前正在执行的函数的前
一个调用中
。
function baz() {
// 当前调用栈是 baz
// 当前的调用位置是全局作用域
console.log("baz");
bar(); // <- bar 的调用位置
}
function bar() {
// 当前调用栈是 baz->bar
// 当前调用位置在 baz 中
console.log("bar");
foo(); // <-foo 的调用位置
}
function foo() {
// 当前调用栈是 baz->bar->foo
// 当前调用位置在 bar 中
console.log("foo");
}
baz(); // <-baz 的调用位置
3、绑定规则
(1)默认绑定
独立
函数被直接调用时,this 默认绑定的就是全局作用域
。
function foo() {
console.log( this.a );
}
var a = 2;
foo(); // 2
在严格模式
下无法使用默认绑定,this 会绑定到 undefined
。
(2)隐式绑定
在调用位置是否有上下文对象,或者是否被某个对象拥有或包含:
function foo() {
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
};
obj.foo(); // 2
以上代码中,foo 声明之后被作为引用属性添加到 obj 中,调用时会隐式
使用 obj 作为上下文。
(3)显式绑定
- 显式使用
call()
或apply()
函数,调用函数时,会把 this 绑定到指定对象上:
function foo() {
console.log(this.a);
}
var obj = {
a: 2
};
foo.call(obj); // 绑定到 obj
- 使用
Function.prototype.bind
,还能解决绑定丢失
问题:
this.x = 9;
var module = {
x: 81,
getX: function() { return this.x; }
};
module.getX(); // 返回 81
var retrieveX = module.getX;
retrieveX(); // 返回 9, 在这种情况下,"this"指向全局作用域
var boundGetX = retrieveX.bind(module); // 将"this"绑定到module对象
boundGetX(); // 返回 81
(4)new 绑定
- 构造函数只是一些使用 new 操作符时被调用的函数。
- 构造函数创建的新对象会绑定到函数的 this。
function foo(a) {
this.a = a;
}
var bar = new foo(2);
console.log(bar.a); // 2