我发现this文章说JavaScript函数调用实际上只是func.call(...)
的语法糖。
我想问一下这是不是真的,因为我没有在规范中找到类似的东西(没有真正彻底检查过,只是简单一瞥并搜索单词call()
)。 / p>
如果有人能够启发我会很高兴,因为如果这篇文章是真的,我对EcmaScript语言的钦佩可能会减少。
答案 0 :(得分:3)
我可以看到为什么这篇文章会说出来,而且在一定程度上也是如此。
他们可能声称这是因为直接使用的函数是未绑定的,这意味着如果我创建了一个对象:
const a = { say: function() { console.log(this.message) } };
a.message = 'hello';
a.say();
当我运行a.say()
函数时,this
内的say()
上下文为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
的{{1}},但在使用say()
进行调用时,最终会使用b
作为其上下文进行调用({{1} })。因此,它基本上等同于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()
。但是,由于它足够兼容,我可以使用NodeList
将其传递给forEach()
,将其转换为带有这些元素的call()
。 (您也可以直接将其提供给Array.prototype.slice
,但我更愿意使用Array
进行转换,然后再做更多事情。)
答案 1 :(得分:0)
当我们调用一个函数时(通过调用表达式,例如foo()或使用call和apply方法),每个函数的[[Call]]内部方法都被激活。
~Dmitry Soshnikov,article关于.bind
仅为某些对象定义的内部属性
内部财产 -
[[Call]]
描述 - 执行与对象关联的代码。通过函数调用表达式调用。参数是
this
对象和包含传递给函数调用表达式的arguments
的列表。实现此内部方法的对象是可调用的。
〜参见表9 here 带注释的ECMAScript 5.1
另请参阅13.2 Creating Function Objects,13.2.1 [[Call]]
,
绑定15.3.4.5,15.3.4.5.1,5 [[Call]]
那里定义的所有步骤当然只有内部,所以没有实际的“desugaring”转换发生,但那些内部步骤真的 DO 类似于它。
我想简而言之,你可以想到他在文章中所说的内容
如何模仿屋顶下发生的事情以更好地理解这个概念。