你不知道的js之this

this

为什么需要 this ?

来看一下下面两段代码

先看不使用 this 的

function identify(context) {
    return context.name.toUpperCase();
}
function speak(context) {
    var greeting = "Hello, I'm " + identify(context); 
  	console.log(greeting);
}
var me = {
    name: "Kyle"
};
var you = {
    name: "Reader"
};
identify(you); // READER
speak(me); //hello, 我是 KYLE

再看使用 this 的

function identify() {
    return this.name.toUpperCase();
}
function speak() {
    var greeting = "Hello, I'm " + identify.call(this); 
  	console.log(greeting);
}
var me = {
    name: "Kyle"
};
var you = {
    name: "Reader"
};
identify.call(me); // KYLE
identify.call(you); // READER
speak.call(me); // Hello, 我是 KYLE 
speak.call(you); // Hello, 我是 READER

也就是说 this 提供了一种更优雅的方式来隐式“传递”一个对象引用,是我们的代码可以更加灵活和易于维护

this 不是什么?

  • this 不一定指向函数自身

  • this 指向函数的作用域。这个问题有点复杂,因为在某种情况下它是正确的,但是在其他情况下它却是错误的,需要明确的是,this 在任何情况下都不指向函数的词法作用域,在 JavaScript 内部,作用 域确实和对象类似,可见的标识符都是它的属性。但是作用域“对象”无法通过 JavaScript 代码访问,它存在于 JavaScript 引擎内部。

this 是什么?

  • this 是在运行时进行绑定
  • this 的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式
  • 当一个函数被调用时,会创建一个活动记录(有时候也称为执行上下文)。这个记录会包 含函数在哪里被调用(调用栈)、函数的调用方法、传入的参数等信息。this 就是记录的 其中一个属性,会在函数执行的过程中用到

this 绑定规则

默认绑定:

首先要介绍的是最常用的函数调用类型: 独立函数调用,也就是默认绑定。可以把这条规则看作是无法应用其他规则时的默认规则。

function foo() {
    console.log(this.a);
}
var a = 2;
foo(); // 2

需要注意的是,默认绑定在严格模式下会无效

隐式绑定

隐式绑定需要考虑的规则是调用位置是否有上下文对象,或者说是否被某个对象拥有或者包含

function foo() {
    console.log(this.a);
}
var obj = {
    a: 2,
    foo: foo
};
obj.foo(); // 2

需要注意的是隐式绑定丢失

function foo() {
    console.log(this.a);
}
var obj = {
    a: 2,
    foo: foo
};
var a = "oops, global"; // a 是全局对象的属性 
setTimeout(obj.foo, 100); // "oops, global"

JavaScript 环境中内置的 setTimeout() 函数实现和下面的伪代码类似:

function** setTimeout(fn,delay) { 
	// 等待 delay 毫秒
 	fn(); // <-- 调用位置!
}

显式绑定

通过 call、apply、bind 进行绑定

new 绑定

通过 new 关键字创建新实例时进行的 this 绑定

this 绑定的优先级

new > 显式绑定 > 隐式绑定 > 默认绑定

⚠️ 如果你把 null 或者 undefined 作为 this 的绑定对象传入 call、apply 或者 bind,这些值在调用时会被忽略,实际应用的是默认绑定规则。

比如

function foo() {
    console.log(this.a);
}
var a = 2;
foo.call(null); // 2
------------- 本文结束 感谢阅读 -------------