我正试图在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();