我有两种情况,我对我得到的输出感到困惑。
案例1:
let x = {
b: 5,
y: function a() {
return function() {
return () => {
console.log(this);
}
}
}
}
x.y()()();
在运行x.y()()()
时,我得到Window
对象作为输出,但是根据箭头函数的定义,输出应该是其父函数。
案例2:
let x = {
b: 5,
y: function a() {
return () => {
console.log(this);
}
}
}
x.y()();
如果我删除一个嵌套级别(这是一个基本示例),然后在运行x.y()()
时,我将得到对象x
作为输出。
您能否解释为什么我确切地得到这些输出?
答案 0 :(得分:2)
第一个函数调用是
x.y()
在该函数调用中,this
将引用x
。该函数调用返回一个函数,该函数将在第二个函数调用中使用:
x.y()()
该函数调用没有显式的this
值,因此this
是window
。该函数调用返回另一个函数,即最里面的箭头函数,该函数根据其定义从其闭包中继承window
作为this
。因此,第三个函数调用:
x.y()()()
还将window
作为this
的值。
答案 1 :(得分:2)
函数内部的this
由其调用上下文以及该函数是否为箭头函数确定。
使用箭头功能,this
始终从外部范围继承。
如果要调用的函数是完整的function
,并且该函数作为对象的属性(例如obj.foo()
)被调用,则调用上下文this
函数中的foo
是obj
。
如果要调用的函数是完整的function
但是独立的-即不是对象的属性-则没有调用上下文,并且this
函数内部将是undefined
或全局对象。
使用
let x = {
b: 5,
y: function a() {
return function() {
return () => {
console.log(this === window);
}
}
}
}
x.y()()();
this
是返回的函数this
的含义-即,此处调用的函数的调用上下文:
x.y()()
被调用的函数不是对象的一部分-它是一个独立的函数表达式,是通过在对象上调用 prior 函数创建的,等效于:
(x.y())()
因此,没有调用上下文,this
是全局对象。
相反,在情况2中,被调用的最接近的祖先function
是对象的a
属性上的y
函数,而该函数是通过调用上下文进行调用:
x.y()()
^^^^^
上面,y
是通过x
的调用上下文来调用的,因此this
是x
函数内的a
。
答案 2 :(得分:0)
您的问题类似于以下问题:-Javascript "this" pointer within nested function
在父对象内部调用函数 -对于x.y(),它有一个前导父x,这就是为什么它返回x -在x.y()()和x.y()()()的情况下,将调用内部函数,该函数没有前导父对象,因此将返回window。
答案 3 :(得分:0)
首先,让我们稍微修改一下代码-但在进行此操作之前,让我们先讨论什至会影响this
:“ CallSite”。
在其中调用函数的位置将确定其this
的值,并且在此确定旁边还有一个先例顺序。基本上,有四种类型的CallSite,但是,有1或2个警告,可以说是5或6种。
这是相当明显和直接的...调用与任何对象分离的函数,this
将成为 Global Scope :
function run() {
this === window === true;
}
隐含的
也相当简单。调用任何函数作为对象的方法,this
将等于该对象的实例。
function run() { return this; }
run(); // Global
({ id: 'test', run: run }).run(); // > { id: 'test', run: f() }
明确的(请参见下面的警告)
直接。使用Function.prototype.call
或Function.prototype.apply
调用函数将 force this
等于原型方法的第一个参数。但是,此规则有一个警告-请继续关注。
(function run() { return this; }).call(new Klass()); // this instanceof Klass === true
新
尽可能简单。调用一个函数,并在调用之前加上new
,this
会等于隐含类的新实例。但是,这确实有一个例外。
Function.prototype.call
和Function.prototype.apply
如果函数是调用Function.prototype.bind
的结果,则不能强制函数的上下文。此外,值得一提的是,在已绑定的函数上调用不会重新绑定到另一个上下文;它的Function.prototype.bind
值将与原始this
调用的值保持不变。
bind
新
在调用带有function run() { return this; }
let o = { };
let x = { };
let r = run.bind(o);
let result = r.call(x); // result === x === false && result === o === true
前缀的函数时,如果该函数返回不同的值,则不会获得隐含类的对象实例。。
new
在原始代码中,您会返回class Class {}
var Klass = function Klass() {
return new Class;
};
var klass = new Klass(); // klass instanceof Class === true
的值,因为箭头功能总是将最外面的作用域放到自己的作用域中。也就是说,箭头功能将始终采用其父级范围的x
上下文。此行为返回返回在函数上调用this
并提供Function.prototype.bind
作为其上下文的结果。
this
当我们调用var x = {
b: 5,
y: function a() {
console.log('a', this);
return function b() {
console.log('b', this); // window
}
return () => {
console.log('=>', this); // x
}
}
}
x.y()();
时,我们将返回该函数返回的任何内容。我已经修改了您的代码以提供两种返回方案:
x.y()
:function b() {...}
是一个分离的功能。因此,其CallSite将为 Global x.y()
:() => {...}
是一个分离的箭头功能。它的行为就像您在规范函数上调用x.y()
并在[parent]函数的bind
上下文中作为第一个参数传递一样。我希望这在进一步了解CallSite之后变得更加有意义。知道了这一点,您就会意识到实际上可以使用this
作为调用策略。也就是说,尝试找出以下代码如何成功运行:
以下两行代码表现出什么行为?
new
编写一个函数,该函数可以补救以下代码以成功运行。
var a = new (function Klass() {})(); // a
var b = new (function Klass() {}()); // b