JavaScript函数调用desugar

时间:2018-02-22 20:18:36

标签: javascript call syntactic-sugar

我发现this文章说JavaScript函数调用实际上只是func.call(...)的语法糖。

我想问一下这是不是真的,因为我没有在规范中找到类似的东西(没有真正彻底检查过,只是简单一瞥并搜索单词call())。 / p>

如果有人能够启发我会很高兴,因为如果这篇文章是真的,我对EcmaScript语言的钦佩可能会减少。

2 个答案:

答案 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 Objects13.2.1 [[Call]]
绑定15.3.4.515.3.4.5.1,5 [[Call]]

那里定义的所有步骤当然只有内部,所以没有实际的“desugaring”转换发生,但那些内部步骤真的 DO 类似于它。

TL;博士

我想简而言之,你可以想到他在文章中所说的内容

  

如何模仿屋顶下发生的事情以更好地理解这个概念。