- 默认绑定
- 隐式绑定
- 显式绑定
- new绑定
this提供了一种更优雅的方式来 隐式“ 传递” 一个对象引用, 因此可以将 API 设计得更加 简洁并且易于复用。
人们很容易把 this 理解成指向函数自身, 这个推断从英语的语法角度来说是说得通的。
this在任何情况下都不指向函数的词法作用域,this 的绑定和函数 声明的位置没有任何关系, 只 取决于函数的调用 方式。
在理解this的绑定过程之前,首先要理解调用位置。最重要的事分析调用栈,我们关心的调用位置就是档期那正在执行的函数的前一个调用中。
默认绑定
首先介绍最常用的调用类型:独立函数调用
function foo() {
console. log( this. a );
}
var a = 2;
foo(); // 2
在本例中,函数调用时应用了this 的默认绑定,因此this只想全局变量
如果使用严格模式,那么全局对象将无法使用默认绑定,因此this会绑定到undefined
隐式绑定
当函数引用又上下文对象时,该规则会把函数调用中的this绑定到这个上下文对象
function foo() {
console. log( this. a );
}
var obj2 = { a: 42, foo: foo };
var obj1 = { a: 2, obj2: obj2 };
obj1\. obj2\. foo(); // 42
隐式丢失
一个最常见 的 this 绑定问题就是被隐式绑定的函数会丢失绑定对象,也就是说它会应用默认绑定,比如将函数传入回调函数的时候。
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"
参数传递其实是一种隐式赋值,因此我们传入的函数也会被隐式赋值。如果把函数传入语言的内置函数而不是自己声明的函数,结果是一样的。
显式绑定
可以使用函数的call和apply方法
function foo() {
console. log( this. a );
}
var obj = { a: 2 };
foo. call( obj ); // 2
通过foo.call(..),我们可以调用foo时强制把它的this绑定到ojb上。如果你传入一个原始值来当作this的绑定对象,这个原始值会被转换成它的对象形式。
new绑定
使用new来调用函数,或者说发生构造函数调用时,会自动执行下面的操作
-
创建一个全新的对象
-
这个新对象会被执行**[[原型]]**连接
-
这个新对象会被绑定到函数调用的
thisfunction foo( a) { this. a = a; }
var bar = new foo( 2);
console. log( bar.a ); // 2
优先级
我们已经了解函数调用中this绑定的四条规则,你需要做的时找到函数的调用位置并判断应用哪条规则。但是,如果某个调用位置可以应用多条规则该怎么办?
new绑定 > 显式绑定 > 隐式绑定 > 默认绑定
绑定例外
被忽略的this
如果你把null或者undefined作为 this 的绑定对象传入call、 apply 或者 bind, 这些值在调 用时会被忽略, 实际应用的是默认绑定规则
间接引用
function foo() {
console. log( this. a );
}
var a = 2;
var o = { a: 3, foo: foo };
var p = { a: 4 };
o. foo(); // 3
(p. foo = o. foo)(); // 2
赋值表达式 p.foo = o.foo 的 返回值是目标函数的引用, 因此调用位置 是 foo() 而不是 p.foo() 或者 o.foo()。 根据 我们之前说过的, 这里会应用默认绑定。
箭头函数
ES6中介绍了一种无法使用这些规则的特殊函数类型,箭头函数
不适用
this的四种标准规则,而是根据外层作用域来决定this
function foo() {
// 返回 一个 箭头 函数
return (a) => {
// this 继承 自 foo()
console. log( this. a );
};
}
var obj1 = { a: 2 };
var obj2 = { a: 3 };
var bar = foo.call( obj1 );
bar.call( obj2 ); // 2, 不是 3!
这其实跟ES6之前代码中的self = this机制一样,箭头函数就是像替代this机制,本质上来说。