你不知道的JS(上卷)——读书笔记8 this全面解析

本文详细解析了JavaScript中的this绑定规则,包括默认绑定、隐式绑定、显式绑定和new绑定,并通过实例解释了它们的工作原理。特别讨论了隐式绑定可能导致的this丢失问题以及显式绑定如何通过call和apply方法指定this。此外,还介绍了箭头函数的this绑定特性,它不再遵循常规规则,而是捕获其所在(词法)上下文的this值。
摘要由CSDN通过智能技术生成

this全面解析

首先,需要找到调用函数的位置,例子代码如下:

function foo() {
  // 调用栈:全局->foo
    console.log('foo');
    bar();
}

function bar() {
    // 调用栈:全局->foo->bar
    console.log('bar');
    baz();
}

function baz() {
    // 调用栈:全局->foo->bar->baz
    console.log('baz');

}

foo(); //从全局开始调用

根据上述的调用栈规则,只要最后调用的函数的上一个函数,那就是他函数所调用的位置,例如baz函数调用的位置位于bar。

搞清楚函数调用位置后,接下来再来了解函数调用时this的绑定规则。

之前说过,this是在函数调用时所绑定的,而this如何被绑定,绑定在哪里,取决于下面四个规则:

  1. 默认绑定
  2. 隐式绑定
  3. 显式绑定
  4. new绑定
默认绑定
function foo() {
    foo.a = 5;
    console.log(this.a);
}

var a = 10;

foo();	//10

像上述代码,由函数直接进行调用,且没有由任何对象引用所调用的,会执行this的默认绑定。在非严格模式下,会将this绑定到全局对象中(也就是this),在严格模式下,this将会绑定为undefined。默认绑定就像他的名字那样:优先级别最低。如果没有其他的绑定规则,那么就会触发默认绑定

隐式绑定
function foo() {
    console.log(this.a);
}

var obj1 = {
    a: 5,
    foo: foo
}

obj1.foo(); //5

如上述代码,foo函数作为obj1对象的成员方法之一调用,所以根据隐式绑定的规则,函数调用时obj1对象会绑定到this上

以及下面这种情况:访问obj1的obj2的foo函数,实际上函数调用位置是在obj2:

function foo() {
    console.log(this.a);
}

var obj1 = {
    a: 5,
    obj2: {
        a: 15,
        foo: foo
    }
}


obj1.obj2.foo(); //15

另外,还需要注意下面这种情况:当把函数的引用赋值到另一个变量时,其函数的调用方式可能会发生改变:

function foo() {
    console.log(this.a);
}

var obj1 = {
    a: 5,
    foo: foo
}

var a = 10;

let bar = obj1.foo;

bar() //5

以及,在使用回调函数时,也应特别注意函数的this绑定丢失:

function foo() {
    setTimeout(function () {
        console.log(this.a);
    }, 100);
}

var obj1 = {
    a: 5,
    foo: foo
}

var a = 10;

obj1.foo();	//10

根据隐式绑定的规则,应该obj1绑定到了this上,可是代码结果显示其this绑定到了全局对象中。
原因是在setTimeout的函数中传入的回调函数,在实际上setTimeout函数中是下面这种:

//类似的代码
function setTimeout(fuc,delay) {
    //...其他代码
    fuc();
}

其中fuc函数就是传入的回调函数,所以实际上函数调用依然是应用了默认绑定(绑定到全局变量中)

隐式绑定的优先级别比默认绑定要高,但是如果使用不当的话可能会导致this绑定丢失

显式绑定

使用函数自带的方法可以实现显式绑定:

function foo() {
    console.log(this.a);
}

var a = 10;

var obj1 = {
    a: 5
}

foo.call(obj1); //5
foo.apply(obj1); //5

其中用call或者apply函数可以显式绑定,第一个参数是要绑定到this的对象
call和apply区别在于之后的参数
对于call来说,传入的所有参数依次像普通函数传参式一个个传入:fuc.call(a,b,c,b,d)
而apply,使得所有参数以数组的形式作为第二个参数:fuc.apply(obj1,[a,b,c,d])

显式绑定明确指定了this所绑定的对象。其优先级比隐式绑定要高

new绑定

new绑定是用new操作符来进行构造函数调用时所产生的的绑定,当用new来调用函数时,会执行以下操作:

  1. 根据传入的参数创建一个对象,如果没有则创建个空对象
  2. 该对象会执行[[prototype]]的链接(将该函数对象的prototype对象与新创建的对象的[[prototype]]相关联)
  3. 该对象会绑定函数调用的this
  4. 如果函数没有返回其他对象(比如返回了字符串、数字等,或者没有return),那么new调用的函数会自动返回这个新创建的对象

箭头函数

ES6出现的新的特殊函数类型,该函数中的this不再适用于之前所写的四种this绑定规则,而是一种全新的规则:this绑定于当前箭头函数外层的作用域

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值