一、对象形式
1、引用函数为箭头函数时
var obj = {
fn: () => console.log(2, this)
}
obj.fn(); // window
const fn = obj.fn
fn(); // window
解释:
-
obj.fn();
:在这种情况下,fn
是作为obj
对象的方法被调用的。然而,fn
是一个箭头函数,它会继承外部作用域的this
值。在全局作用域中,箭头函数的外部作用域是全局作用域,因此this
指向全局对象(在浏览器中是window
)。所在的作用域其实是最外层的js环境,因为没有其他函数包裹;然后最外层的js环境指向的对象是winodw对象,所以这里的this指向的是window对象。 -
const fn = obj.fn; fn();
:在这种情况下,fn
是将obj.fn
赋值给一个常量。由于obj.fn
是一个箭头函数,它会继承外部作用域的this
值。在这里,箭头函数的外部作用域是全局作用域,因此this
指向全局对象(在浏览器中是window
)。所以,console.log(2, this)
会打印出window
。
总结起来,无论是通过 obj.fn()
还是通过 fn()
调用箭头函数,this
都指向全局对象 window
。这是因为箭头函数继承了外部作用域的 this
值,而不是创建自己的 this
值。
疑问:那么如何使this一直指向obj?
var name = 'window'
const obj2 = {
name: '杜甫',
}
var obj = {
name: '李白',
fn: function () {
return () => console.log(this.name)
}
}
const fn = obj.fn();
fn() // 李白
fn.call(obj2) // 李白
fn.call() // 李白
解释:
-
fn() // 李白
:在这种情况下,fn
是作为obj
对象的方法被调用的。obj.fn()
返回一个箭头函数,并将其赋值给了fn
。由于箭头函数继承了外部作用域的this
值,所以this.name
指向obj
对象的name
属性,即'李白'
。因此,console.log(this.name)
打印出'李白'
。 -
fn.call(obj2) // 李白
:在这种情况下,虽然使用了call
方法将fn
的执行上下文更改为obj2
,但是箭头函数仍然继承了外部作用域的this
值。由于箭头函数的外部作用域是在fn
被定义时确定的,它是obj
对象的方法,所以this.name
仍然指向obj
对象的name
属性,即'李白'
。因此,console.log(this.name)
打印出'李白'
。 -
fn.call() // 李白
:在这种情况下,call
方法没有传递任何参数,因此fn
的执行上下文仍然是全局对象(在浏览器中是window
)。由于箭头函数继承了外部作用域的this
值,所以this.name
指向全局对象的name
属性,即'window'
。然而,在全局作用域中并没有定义名为name
的变量,所以this.name
的值是undefined
。因此,console.log(this.name)
打印出undefined
。
总结起来,无论如何改变箭头函数的执行上下文,它仍然会继承外部作用域的 this
值。在这段代码中,箭头函数继承了 obj
对象的方法的 this
值,因此无论如何调用箭头函数,this.name
都指向 obj
对象的 name
属性,即 '李白'
。
2、引用函数为普通函数时
var obj = {
fn: function () {
console.log(this);
}
}
obj.fn(); // obj
const fn = obj.fn
fn(); // window
解释:
this
的值取决于函数如何被调用。这就是所谓的函数调用的上下文(context)。以下是对这段代码的分析:
-
obj.fn();
:在这种情况下,fn
是作为obj
对象的方法被调用的。因此,this
在fn
函数内部指向obj
。这就是为什么console.log(this);
会打印出obj
对象。 -
const fn = obj.fn; fn();
:在这种情况下,fn
是作为一个独立的函数被调用的,而不是作为obj
的方法。在非严格模式下,当一个函数独立调用(即它不是作为对象的方法调用)时,this
通常会指向全局对象(在浏览器中是window
)。因此,console.log(this);
会打印出window
。如果你在严格模式下运行这段代码(即在代码的顶部添加"use strict";
),this
会是undefined
,因为严格模式下,独立函数调用不会默认this
到全局对象。
这就是为什么在这段代码中,this
在两种情况下有不同的值。
疑问:对象嵌套的情况呢?
var name = 'window'
var obj = {
name: '李白',
age: {
name: 'age',
fn: function () { console.log(this.name) }
}
};
obj.age.fn() //age
同上述一样,箭头函数指向window,解构出来也是window,如果是普通函数就是所在对象本身
三、进阶
var name = 'window'
var obj = {
name: '李白',
fn: () => console.log(this.name),
fn2: function () { console.log(this.name) }
};
(obj.fn = obj.fn)(); //window
(obj.fn2 = obj.fn2)() //window
-
(obj.fn = obj.fn)(); // window
:在这种情况下,obj.fn
是一个箭头函数,并将其赋值给了obj.fn
。然后,(obj.fn = obj.fn)
表达式将箭头函数赋值给了obj.fn
,但是由于箭头函数继承了外部作用域的this
值,所以this.name
指向全局对象(在浏览器中是window
)。因此,console.log(this.name)
打印出'window'
。 -
(obj.fn2 = obj.fn2)(); // window
:在这种情况下,obj.fn2
是一个普通函数,并将其赋值给了obj.fn2
。然后,(obj.fn2 = obj.fn2)
表达式将普通函数赋值给了obj.fn2
。普通函数的this
值是在执行时确定的,而不是在定义时确定的。因此,当(obj.fn2 = obj.fn2)()
被调用时,this
指向全局对象(在浏览器中是window
)。因此,console.log(this.name)
打印出'window'
。
无论是箭头函数还是普通函数,当它们作为对象的方法被调用时,它们的 this
值都指向全局对象 window
。这是因为在这段代码中,对象的方法被直接调用,而不是通过对象的引用进行调用。因此,函数的执行上下文是全局对象。