在Nodejs中的Array原型上调用自定义方法



我正试图在Array对象的原型上添加一个自定义方法:

Array.prototype.demo = function(){
this.forEach(i=>console.log(i))
}

但是,当我调用这样的方法时,我收到了下面的错误:

[1,2,3].demo()
// Error: TypeError: Cannot read property 'demo' of undefined

然而,当我将其更改为:时,它运行成功

const arr = [1,2,3];
arr.demo()
// Output: 1, 2, 3

PS。这在nodejs中要在浏览器中重现错误,请立即复制/粘贴整个块,然后单击enter。

更新:听起来我们需要添加一个分号才能使其工作:

Array.prototype.demo = function(){
this.forEach(i=>console.log(i))
};   <=== added semicolon here to work @jfriend00
[1,2,3].demo();

然而,现在下一个代码在没有分号的情况下工作!!

String.prototype.demo = function(){
this.split('').forEach(c=>console.log(c))
}
'hello'.demo();

快速修复-添加分号

在函数定义的末尾添加一个分号:

Array.prototype.demo = function(){
this.forEach(i=>console.log(i))
};    // <======
[1,2,3].demo();

而且,它会起作用的。

发生了什么

问题是[1,2,3]正与前一个函数组合(它们之间的空白折叠(。在这种情况下,[1,2,3]变成[3],并尝试从函数对象读取[3]属性。如果将分号放在函数定义的末尾,则表示函数定义语句的结束,然后[1,2,3]可以被解释为静态数组定义。

这一切都与上下文有关。在Javascript中的某些情况下,[x]是一个属性访问。在其他情况下,它是一个静态数组定义。如果没有分号,它将被解释为属性访问,而不是数组定义。

请记住,函数是Javascript中的对象,因此它们可以具有属性,并可以作为属性访问对[x]进行响应。

所以,如果函数末尾没有分号,你基本上就有了这个:

Array.prototype.demo = function() {...}[3].demo();

因为空白被折叠在函数的末尾和[1,2,3]之间。这意味着JS解释器期望[]是一个属性名称,因此它评估[]内部的语句,并且在该上下文中[1,2,3]变为[3](评估1,2,3,它取最后一个逗号分隔语句3的值(。

更多详细说明

这样想:

// defines function
let f = function() {};       
// attempts to read a property from that function object
let o = f [1,2,3];           // this is the same as let o = f[3]
// tries to call `.demo()` on the value read from that property
// which was undefined so this throws
o.demo();

函数是对象

作为函数如何成为对象的演示,请参阅这个实际工作的示例!

// defines function
let f = function() {};       
f[3] = {demo: function() { console.log("demo!!!");}}
// attempts to read a property from that function object
let o = f[1,2,3];           // this is the same as let o = f[3]
// tries to call `.demo()` on the value read from that property
// which was undefined so this throws
o.demo();

在这里,我们实际上在函数的[3]属性上放置了一个属性,所以当f[1,2,3]读取该属性时,它实际上得到了一个带有.demo()方法的对象,所以当我们调用它时,一切都正常。我并不是建议人们用这种方式进行编码,但我试图说明f[1,2,3]是如何从函数对象中读取[3]属性的。

不遗漏分号的充分理由

这些奇怪的情况是一个很好的理由,不要遗漏分号,即使你通常(但并不总是(可以逃脱惩罚

原因是函数是对象,所以如果我们不添加分号,JavaScript将尝试访问函数对象上的属性,然后对逗号运算符求值,如下所示:

function() { ... }[1,2,3].demo();
function() { ... }[3].demo();
undefined.demo();

最新更新