对于这种情况,我对箭头函数中的 'this' 关键字感到困惑
I am confused with the 'this' keyword in arrow function for this case
我有两种情况,我对得到的输出感到困惑。
案例一:
let x = {
b: 5,
y: function a() {
return function() {
return () => {
console.log(this);
}
}
}
}
x.y()()();
在 运行 x.y()()()
我得到 Window
对象作为输出,但根据箭头函数的定义,输出应该是它的父函数。
案例二:
let x = {
b: 5,
y: function a() {
return () => {
console.log(this);
}
}
}
x.y()();
如果我删除一层嵌套,这是一个基本示例,那么在 运行 x.y()()
上,我将得到对象 x
作为输出。
你能解释一下为什么我会得到这些输出吗?
第一个函数调用是
x.y()
在该函数调用中,this
将引用 x
。该函数调用returns一个函数,在第二个函数调用中使用:
x.y()()
函数调用没有明确的 this
值,因此 this
是 window
。该函数调用 returns 另一个 函数,最里面的箭头函数,根据其定义从其闭包中继承 window
作为 this
。因此第三个函数调用:
x.y()()()
也有 window
作为 this
的值。
函数内部的 this
由其调用上下文以及函数是否为箭头函数决定。
使用箭头函数,this
总是从外部作用域继承。
如果被调用的函数是完整的 function
和 则该函数被调用为 属性 作为对象(例如 obj.foo()
),那么调用上下文,foo
函数里面的this
,就是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
被调用是对象y
属性上的a
函数,而这个函数是调用的调用上下文:
x.y()()
^^^^^
上面,y
是用 x
的调用上下文调用的,所以 this
在 a
函数中是 x
。
你的问题与这个问题类似:-Javascript "this" pointer within nested function
在父对象内部调用函数
- 在 x.y() 的情况下,它有一个领先的父 x,这就是它 returned x 的原因
- 在 x.y()() & x.y()()() 的情况下,内部函数被调用,它没有前导父对象,因此将 return window.
这是怎么回事...
首先,让我们稍微修改一下您的代码——但在我们这样做之前,让我们谈谈 甚至影响 this
的因素:"CallSite"。
CallSite
调用函数的位置将决定它的 this
值,并且有一个 先例顺序 伴随着这种决定。基本上,有 4 种类型的 CallSite,然而,有 1 或 2 个警告可以说是这 5 或 6 种类型。
4 种 CallSite
- 全球
- 隐式
- 显式
- 新建
全球的
这是相当明显和直接的...调用一个与任何对象分离的函数,this
将是 全局作用域:
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
调用函数将 强制 this
等于原型方法的第一个参数。但是,这一规则有一个警告 -- 敬请期待。
(function run() { return this; }).call(new Klass()); // this instanceof Klass === true
新的
尽可能简单明了。调用函数并在调用前加上 new
和 this
将等于隐含的 class 的新实例。但是,这确实有一个例外。
CallSite 优先级注意事项
明确的
如果函数是调用 Function.prototype.bind
的结果,Function.prototype.call
& Function.prototype.apply
不能强制函数的上下文。此外,值得注意的是 调用 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
为前缀的函数时,如果函数 return 是不同的,则您将不会获得隐含 class 的对象实例值.
class Class {}
var Klass = function Klass() {
return new Class;
};
var klass = new Klass(); // klass instanceof Class === true
您的代码(已修改)
在您的原始代码中,您得到了 x
的值,因为 Arrow-Functions 总是将最外层的作用域渗入到它们自己的作用域中 。也就是说,箭头函数将始终采用其 父作用域的 this
上下文 。此行为 与 return 在函数上调用 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()
时,我们正在 returning 那个函数 return。我修改了您的代码以呈现两个 return 场景:
- 返回
function b() {...}
:x.y()
是一个分离函数。因此,它的 CallSite 将是 Global
- 返回
() => {...}
:x.y()
是一个分离的箭头函数。它的行为就像您在规范函数上调用 bind
并将 [parent] 函数的 this
上下文作为第一个参数传递。
关闭
我希望在进一步了解 CallSite 之后这会更有意义。知道了这一点,您就会意识到可以实际使用 new
作为调用策略。也就是说,尝试找出以下代码如何 运行 成功:
练习 1("Crockford Dog Balls Problem")
以下两行代码表现出什么行为?
var a = new (function Klass() {})(); // a
var b = new (function Klass() {}()); // b
练习 2 ("What's New?")
编写一个函数来修复以下代码 运行 成功。
var instance = new new new new Klass();
希望对您有所帮助!
我有两种情况,我对得到的输出感到困惑。
案例一:
let x = {
b: 5,
y: function a() {
return function() {
return () => {
console.log(this);
}
}
}
}
x.y()()();
在 运行 x.y()()()
我得到 Window
对象作为输出,但根据箭头函数的定义,输出应该是它的父函数。
案例二:
let x = {
b: 5,
y: function a() {
return () => {
console.log(this);
}
}
}
x.y()();
如果我删除一层嵌套,这是一个基本示例,那么在 运行 x.y()()
上,我将得到对象 x
作为输出。
你能解释一下为什么我会得到这些输出吗?
第一个函数调用是
x.y()
在该函数调用中,this
将引用 x
。该函数调用returns一个函数,在第二个函数调用中使用:
x.y()()
函数调用没有明确的 this
值,因此 this
是 window
。该函数调用 returns 另一个 函数,最里面的箭头函数,根据其定义从其闭包中继承 window
作为 this
。因此第三个函数调用:
x.y()()()
也有 window
作为 this
的值。
函数内部的 this
由其调用上下文以及函数是否为箭头函数决定。
使用箭头函数,this
总是从外部作用域继承。
如果被调用的函数是完整的 function
和 则该函数被调用为 属性 作为对象(例如 obj.foo()
),那么调用上下文,foo
函数里面的this
,就是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
被调用是对象y
属性上的a
函数,而这个函数是调用的调用上下文:
x.y()()
^^^^^
上面,y
是用 x
的调用上下文调用的,所以 this
在 a
函数中是 x
。
你的问题与这个问题类似:-Javascript "this" pointer within nested function
在父对象内部调用函数 - 在 x.y() 的情况下,它有一个领先的父 x,这就是它 returned x 的原因 - 在 x.y()() & x.y()()() 的情况下,内部函数被调用,它没有前导父对象,因此将 return window.
这是怎么回事...
首先,让我们稍微修改一下您的代码——但在我们这样做之前,让我们谈谈 甚至影响 this
的因素:"CallSite"。
CallSite
调用函数的位置将决定它的 this
值,并且有一个 先例顺序 伴随着这种决定。基本上,有 4 种类型的 CallSite,然而,有 1 或 2 个警告可以说是这 5 或 6 种类型。
4 种 CallSite
- 全球
- 隐式
- 显式
- 新建
这是相当明显和直接的...调用一个与任何对象分离的函数,this
将是 全局作用域:
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
调用函数将 强制 this
等于原型方法的第一个参数。但是,这一规则有一个警告 -- 敬请期待。
(function run() { return this; }).call(new Klass()); // this instanceof Klass === true
新的
尽可能简单明了。调用函数并在调用前加上 new
和 this
将等于隐含的 class 的新实例。但是,这确实有一个例外。
CallSite 优先级注意事项
明确的 如果函数是调用Function.prototype.bind
的结果,Function.prototype.call
& Function.prototype.apply
不能强制函数的上下文。此外,值得注意的是 调用 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
为前缀的函数时,如果函数 return 是不同的,则您将不会获得隐含 class 的对象实例值.
class Class {}
var Klass = function Klass() {
return new Class;
};
var klass = new Klass(); // klass instanceof Class === true
您的代码(已修改)
在您的原始代码中,您得到了 x
的值,因为 Arrow-Functions 总是将最外层的作用域渗入到它们自己的作用域中 。也就是说,箭头函数将始终采用其 父作用域的 this
上下文 。此行为 与 return 在函数上调用 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()
时,我们正在 returning 那个函数 return。我修改了您的代码以呈现两个 return 场景:
- 返回
function b() {...}
:x.y()
是一个分离函数。因此,它的 CallSite 将是 Global - 返回
() => {...}
:x.y()
是一个分离的箭头函数。它的行为就像您在规范函数上调用bind
并将 [parent] 函数的this
上下文作为第一个参数传递。
关闭
我希望在进一步了解 CallSite 之后这会更有意义。知道了这一点,您就会意识到可以实际使用 new
作为调用策略。也就是说,尝试找出以下代码如何 运行 成功:
练习 1("Crockford Dog Balls Problem")
以下两行代码表现出什么行为?
var a = new (function Klass() {})(); // a
var b = new (function Klass() {}()); // b
练习 2 ("What's New?")
编写一个函数来修复以下代码 运行 成功。
var instance = new new new new Klass();