[TLDR]Javascript中关于this机制的四条规则

微信扫一扫,分享到朋友圈

[TLDR]Javascript中关于this机制的四条规则
  1. 默认绑定
  2. 隐式绑定
  3. 显式绑定
  4. 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
来调用函数,或者说发生构造函数调用时,会自动执行下面的操作

  1. 创建一个全新的对象

  2. 这个新对象会被执行 [[原型]]
    连接

  3. 这个新对象会被绑定到函数调用的 this

    function 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
机制,本质上来说。

微信扫一扫,分享到朋友圈

[TLDR]Javascript中关于this机制的四条规则

年轻人一真香,拼多多就笑了

上一篇

Java线程池的了解使用—筑基篇

下一篇

你也可能喜欢

[TLDR]Javascript中关于this机制的四条规则

长按储存图像,分享给朋友