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
关键字来调用父类的方法,而箭头函数不会绑定自己的this
或super
。但是,如果确实在类的方法中使用了箭头函数,它会捕获类实例化时构造函数的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,和该“对象“没有关系,取决于定义对象时所处的上下文。因为定义箭头函数时,对象还没有创建出来。