JavaScript 函数调用脱糖
JavaScript function call desugar
我发现 this 文章说 JavaScript 函数调用实际上只是 func.call(...)
的语法糖。
我想问一下这是不是真的,因为我在规范中没有找到类似的内容(还没有真正彻底检查过,只是简单浏览并搜索 call()
这个词) .
如果有人能开导我就太好了,因为如果这篇文章是真的,我对 EcmaScript 语言的钦佩可能会减少。
我明白为什么文章会这么说,而且在某种程度上是这样。
他们声称的原因可能是因为直接使用的函数是未绑定的,这意味着如果我创建一个对象:
const a = { say: function() { console.log(this.message) } };
a.message = 'hello';
a.say();
当我运行函数a.say()
时,say()
中的this
上下文是a
。那相当于 a.say.call(a)
.
因为我没有显式绑定那个函数,如果我把它传递到其他地方可以调用它,它就不一定再有 a
的上下文了:
const a = { say: function() { console.log(this.message) } };
const b = {};
a.message = 'hello';
b.message = 'goodbye';
b.say = a.say;
b.say();
请注意,即使我复制了 a
的 say()
,当使用 b
调用时,它最终还是使用 b
调用,因为它是上下文(this
).因此,它本质上等同于 a.say.call(b)
.
如果您显式绑定函数,那么它将始终使用固定的上下文:
const a = { say: function() { console.log(this.message); } };
const b = {};
a.message = 'hello';
b.message = 'goodbye';
b.say = a.say.bind(a);
b.say();
绑定后,它现在将始终使用 a
的上下文,即使我可能会将函数传递到其他地方。
话虽如此,我不确定为什么您的钦佩会受到影响。实际上,我发现这是该语言的一个很棒的特性,它使它非常强大和灵活。它允许你做这样的事情:
Array.prototype.slice.call(document.querySelectorAll('div'))
.forEach(el => console.log(el.innerHTML));
<div>A</div>
<div>B</div>
<div>C</div>
在那个例子中,document.querySelectorAll()
returns a NodeList
,通常没有 forEach()
。但是,由于它足够兼容,我可以使用 call()
将其传递给 Array.prototype.slice
以将其转换为具有这些元素的 Array
。 (你也可以直接把它给forEach()
,但我更喜欢用slice()
转换它然后做进一步的事情。)
The [[Call]] internal method of every function is activated when we call a function (via the call expression, e.g. foo() or with using call and apply methods).
~ Dmitry Soshnikov, article 关于 .bind
Internal Properties Only Defined for Some Objects
Internal Property - [[Call]]
Description - Executes code associated with the object. Invoked via a function call expression. The arguments are a this
object and a list containing the arguments
passed to the function call expression. Objects that implement this internal method are callable.
~ 请参阅 Table 9 here at 带注释的 ECMAScript 5.1
另见 13.2 Creating Function Objects、13.2.1 [[Call]]
、
绑定 15.3.4.5, 15.3.4.5.1,5 [[Call]]
那里定义的所有步骤当然只是内部步骤,因此不会发生实际的“脱糖”转换,但这些内部步骤确实 DO 类似。
tl;博士
我猜,简而言之,你可以把他在文章中说的想成
How to mimick what's going on under the roof to better understand the concept.
我发现 this 文章说 JavaScript 函数调用实际上只是 func.call(...)
的语法糖。
我想问一下这是不是真的,因为我在规范中没有找到类似的内容(还没有真正彻底检查过,只是简单浏览并搜索 call()
这个词) .
如果有人能开导我就太好了,因为如果这篇文章是真的,我对 EcmaScript 语言的钦佩可能会减少。
我明白为什么文章会这么说,而且在某种程度上是这样。
他们声称的原因可能是因为直接使用的函数是未绑定的,这意味着如果我创建一个对象:
const a = { say: function() { console.log(this.message) } };
a.message = 'hello';
a.say();
当我运行函数a.say()
时,say()
中的this
上下文是a
。那相当于 a.say.call(a)
.
因为我没有显式绑定那个函数,如果我把它传递到其他地方可以调用它,它就不一定再有 a
的上下文了:
const a = { say: function() { console.log(this.message) } };
const b = {};
a.message = 'hello';
b.message = 'goodbye';
b.say = a.say;
b.say();
请注意,即使我复制了 a
的 say()
,当使用 b
调用时,它最终还是使用 b
调用,因为它是上下文(this
).因此,它本质上等同于 a.say.call(b)
.
如果您显式绑定函数,那么它将始终使用固定的上下文:
const a = { say: function() { console.log(this.message); } };
const b = {};
a.message = 'hello';
b.message = 'goodbye';
b.say = a.say.bind(a);
b.say();
绑定后,它现在将始终使用 a
的上下文,即使我可能会将函数传递到其他地方。
话虽如此,我不确定为什么您的钦佩会受到影响。实际上,我发现这是该语言的一个很棒的特性,它使它非常强大和灵活。它允许你做这样的事情:
Array.prototype.slice.call(document.querySelectorAll('div'))
.forEach(el => console.log(el.innerHTML));
<div>A</div>
<div>B</div>
<div>C</div>
在那个例子中,document.querySelectorAll()
returns a NodeList
,通常没有 forEach()
。但是,由于它足够兼容,我可以使用 call()
将其传递给 Array.prototype.slice
以将其转换为具有这些元素的 Array
。 (你也可以直接把它给forEach()
,但我更喜欢用slice()
转换它然后做进一步的事情。)
The [[Call]] internal method of every function is activated when we call a function (via the call expression, e.g. foo() or with using call and apply methods).
~ Dmitry Soshnikov, article 关于 .bind
Internal Properties Only Defined for Some Objects
Internal Property -
[[Call]]
Description - Executes code associated with the object. Invoked via a function call expression. The arguments are a
this
object and a list containing thearguments
passed to the function call expression. Objects that implement this internal method are callable.
~ 请参阅 Table 9 here at 带注释的 ECMAScript 5.1
另见 13.2 Creating Function Objects、13.2.1 [[Call]]
、
绑定 15.3.4.5, 15.3.4.5.1,5 [[Call]]
那里定义的所有步骤当然只是内部步骤,因此不会发生实际的“脱糖”转换,但这些内部步骤确实 DO 类似。
tl;博士
我猜,简而言之,你可以把他在文章中说的想成
How to mimick what's going on under the roof to better understand the concept.