每个函数的 this 是在调用 时被绑定的,完全取决于函数的调用位置
默认绑定
独立函数调用
function foo() {
console.log( this.a );
}
var a = 2;
foo(); // 2
foo() 是直接使用不带任何修饰的函数引用进行调用的,因此只能使用 默认绑定,无法应用其他规则
function foo() {
"use strict";
console.log( this.a );
}
var a = 2;
foo(); // TypeError: this is undefined
虽然 this 的绑定规则完全取决于调用位置,但是只 有 foo() 运行在非 strict mode 下时,默认绑定才能绑定到全局对象;严格模式下与 foo() 的调用位置无关
隐式绑定
调用位置是否有上下文对象,或者说是否被某个对象拥有或者包含。
function foo() {
console.log( this.a );
}
var obj = {
a: 2,
foo: foo
};
obj.foo(); // 2
- 对象属性引用链中只有最顶层或者说最后一层会影响调用位置
function foo() {
console.log( this.a );
}
var obj2 = {
a: 42,
foo: foo
};
var obj1 = {
a: 2,
obj2: obj2
};
obj1.obj2.foo(); // 42
- 隐式丢失
function foo() {
console.log( this.a );
}
var obj = {
a: 2,
foo: foo
};
var bar = obj.foo; // 函数别名!
var a = "oops, global"; // a 是全局对象的属性 bar(); // "oops, global"
function foo() {
console.log( this.a );
}
function doFoo(fn) {
// fn 其实引用的是 foo
fn(); // <-- 调用位置!
}
var obj = {
a: 2,
foo: foo
};
var a = "oops, global"; // a 是全局对象的属性 doFoo( obj.foo ); // "oops, global"
显式绑定
bind call apply
从this 绑定的角度来说,call(..) 和 apply(..) 是一样的,它们的区别体现 在其他的参数上。
- 硬绑定
显式的强制绑定
function foo(something) { console.log( this.a, something ); return this.a + something; } var obj = { a:2 }; var bar = function() { return foo.apply( obj, arguments ); }; var b = bar( 3 ); // 2 3
- API调用的“上下文”
function foo(el) { console.log( el, this.id ); } // 调用 foo(..) 时把 this 绑定到 obj var obj = { id: "awesome" }; [1, 2, 3].forEach( foo, obj ); // 1 awesome 2 awesome 3 awesome
new绑定
使用 new 来调用函数,或者说发生构造函数调用时,会自动执行下面的操作。
- 创建(或者说构造)一个全新的对象。
- 这个新对象会被执行 [[ 原型 ]] 连接。
- 这个新对象会绑定到函数调用的 this。
- 如果函数没有返回其他对象,那么 new 表达式中的函数调用会自动返回这个新对象。
function foo(a) {
this.a = a;
}
var bar = new foo(2);
console.log( bar.a ); // 2