深入理解JavaScript - 全面解析箭头函数的this值

本文详细解释了箭头函数中this值的绑定规则,指出它并不创建自己的this上下文,而是继承定义时的上下文。通过各种场景分析,包括全局、普通函数、对象和类中的箭头函数,揭示了其动态与静态特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

t

箭头函数中的this永远指向全局对象? 不是!!!!!!

箭头函数中并没有this值,在箭头行数中使用this时,会像捕获定义时所在上下文的this值作为自己的this值。

研究过箭头函数的同学应该看过或听过这句话: 箭头函数中的 this是在定义时绑定的,而不是在调用时绑定 这句话很容易让人误认为箭头函数的this值是固定的 , 其实不然 .

如果箭头函数定义在一个普通函数中 , 那么函数的this值是这个函数this , 而普通函数的this是在调用时绑定的,也就是说普通函数的this值是动态的,所以在普通函数中定义的箭头函数的this也是动态的.

分情况讨论箭头函数定义时的上下文

当讨论箭头函数定义时的上下文时,我们需要考虑箭头函数是在哪里定义的,以及它如何捕获其外围的this值。以下是一些不同情况的分析:

1. 在全局作用域中定义

如果箭头函数是在全局作用域中定义的,定时的上下文是全局对象,所以它会捕获全局对象(在浏览器中为window)的this值。

let globalArrow = () => {
    console.log(this); // 输出全局对象,通常是 window
};
globalArrow();

2. 在普通函数内部定义

如果箭头函数是在普通函数内部定义的,它会捕获这个普通函数执行时的this值。

⚠️⭐️ ⭐️ ⭐️ ⭐️ ⭐️ 普通函数的上下文是动态的,所以箭头函数的上下文也跟着是动态的。

(1)直接调用普通函数

function outerFunction() {
    this.a = 'outer';
    let arrowInOuterFunction = () => {
        console.log(this, this.a);// window,outer
    };
    arrowInOuterFunction();
}
outerFunction();

箭头函数中的this打印出window,因为函数的执行上下文是全局对象,所以箭头函数的执行上下文也是全局对象,this.value打印的是outer,因为this.value = ‘outer’ 这行代码在全局对象中设置了value值为outer。
在这里插入图片描述

(2)将普通函数赋值给对象的属性

function outerFunction() {
    this.a = 'outer';
    let arrowInsideOuterFunction = () => {
        console.log(this,this.a);// {a: 'outer', b: 'obj.b', f: ƒ} 'outer'
    };
    arrowInsideOuterFunction();
}
//outerFunction();

const obj = { a:"obj.a",b:"obj.b"};
obj.f = outerFunction;
obj.f();

obj.f = outerFunction在obj对象下添加了一个属性f,引用了outerFunction函数对象,执行obj.f(),即执行outerFunction时,执行的上下文为obj对象,执行函数时将obj下的a赋值为outer

(3)使用call

function outerFunction() {
    this.a = 'outer';
    let arrowInsideOuterFunction = () => {
        console.log(this, this.a);// {a: 'outer', b: 'obj.b', f: ƒ} 'outer'
    };
    arrowInsideOuterFunction();
}
const obj = { a: "obj.a", b: "obj.b" };
outerFunction.call(obj)

outerFunction.call(obj)将函数的上下文this设置为obj, 输出和上个例子程序一样。

3. 在对象字面量中定义箭头函数

如果箭头函数是在一个对象中定义的,此时的上下文不是这个对象,而是定义该对象时所处的上下文。因为定义对象时对象还没有创建成功。

(1)全局作用域中的对象

let obj = {
    a: 'obj.a',
    b: 'obj.b',
    arrowFunctionInObj: () => {
        console.log(this,this.a); // window,undefined
    }
};
obj.arrowFunctionInObj();

(2)普通函数中的对象

箭头函数定义在普通函数中的对象中,其上下文就取决于函数的上下文了。函数的上下文是动态的,取决于函数的调用方式。

例:

function outer() {
    let innerObj = {
        a: 'innerObj.a',
        b: 'innerObj.b',
        arrowInInnerObj: () => {
            console.log(this, this.a); 
        }
    };
    innerObj.arrowInInnerObj();
}
outer();        // window,undefined

let obj = { a: 'obj.a', b: 'obj.b'};
obj.f = outer;
obj.f();        // {a: 'obj.a', b: 'obj.b', f: ƒ} 'obj.a'

如果想让arrowInInnerObj输出innerObj 的内容怎么办?只要将其修改为普通函数就可以了

function outer() {
    let innerObj = {
        a: 'innerObj.a',
        b: 'innerObj.b',
        normalInInnerObj: function(){
            console.log(this, this.a);
        }
    };
    innerObj.normalInInnerObj();
}
outer(); // {a: 'innerObj.a', b: 'innerObj.b', normalInInnerObj: ƒ} 'innerObj.a'

let obj = { a: 'obj.a', b: 'obj.b' };
obj.f = outer;
obj.f(); // {a: 'innerObj.a', b: 'innerObj.b', normalInInnerObj: ƒ} 'innerObj.a'

(3)对象中的对象

对象中的对象中定义的箭头函数,取决于定义对象时的上下文。这里就不给出示例程序了。

4、箭头函数作为参数

(1)全局作用域中定义的箭头函数

全局作用域中定义的箭头函数的this,在任何时候都是全局对象。因为它定义在全局上下文中。

let arrow_f = () => { console.log(this, this.a); }

function outer(f) {
    f();
}
outer(arrow_f);

let obj = {
    a: 'obj.a',
    b: 'obj.b',
};
obj.f = outer;
obj.f(arrow_f)

(2)函数中定义的箭头函数

函数中定义的箭头函数的this取决于函数的上下文,函数的上下文是动态的,取决于调用函数的方式。

function outer2(f) {
    let arrow_f = () => { console.log(this, this.a); }
    arrow_f();
}
outer2();           // window

let obj = {
    a: 'obj.a',
    b: 'obj.b',
};
obj.f = outer2;
obj.f();            // {a: 'obj.a', b: 'obj.b', f: ƒ} 'obj.a'

4. 在类的方法中定义

在ES6的类中,通常不会直接在方法中使用箭头函数,因为类的方法应该能够通过super关键字来调用父类的方法,而箭头函数不会绑定自己的thissuper。但是,如果确实在类的方法中使用了箭头函数,它会捕获类实例化时构造函数的this值。

class MyClass {
    constructor() {
        this.value = 'class';
    }
    arrowMethod = () => {
        console.log(this.value); // 输出 'class',但通常不推荐在类的方法中使用箭头函数
    }
}

const instance = new MyClass();
instance.arrowMethod(); // 输出 'class'

在类中使用箭头函数通常不是一个好的做法,因为它破坏了类实例方法应有的行为(如绑定this到实例上)。

总结

箭头函数定义时的上下文决定了它如何捕获的this值。箭头函数不会创建自己的this上下文,而是从外围作用域(函数或全局作用域)继承this值。因此,在定义箭头函数时,需要特别注意它所在的上下文,以确保this指向预期的对象。如果需要在函数内部使用与对象实例绑定的this,通常应该使用普通函数而不是箭头函数。

练习

练习1:在全局作用域中定义箭头函数

let arrowInGloble = () => { console.log(this, this.a); }
arrowInGloble();    // window undefined

let obj = { a: "obj.a", b: "obj.b" };

obj.f = arrowInGloble;
obj.f();           // window undefined

解析:全局作用域中定义的箭头函数,它的this永远都是全局对象。

练习2:普通函数中定义箭头函数

let normalFunction = function () {
    let arrowInNormalFunction = () => {
        console.log(this, this.a);
    }
    arrowInNormalFunction();
}
normalFunction();   // window undefined

let obj = { a: "obj.a", b: "obj.b" };
obj.f = normalFunction;
obj.f();            // {a: 'obj.a', b: 'obj.b', f: ƒ} 'obj.a'

解析:在普通函数中定义的箭头函数,它的this指向这个普通函数的上下文,而这个函数的上下文是动态的,即取决于调用函数的方式。在全局作用域中调用,它的上下文就是全局对象,在对象中调用,它的上下文就是该对象。

练习3:普通函数中的对象中定义箭头函数

let normalFunction = function () {
    let objInNormalFunction = {
        a: "objInNormalFunction.a",
        b: "objInNormalFunction.b",
        _arrow: () => {
            console.log(this, this.a);
        }
    }
    objInNormalFunction._arrow();
}
normalFunction();       // window undefined

let obj = { a: "obj.a", b: "obj.b" };
obj.f = normalFunction;
obj.f();               // {a: 'obj.a', b: 'obj.b', f: ƒ} 'obj.a'

对象定义中的箭头函数的this,和该“对象“没有关系,取决于定义对象时所处的上下文。因为定义箭头函数时,对象还没有创建出来。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

java硕哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值