有一天,我在编写游戏时错误地遇到了这个问题:
var foo = function() { alert("Hello, World!"); }
foo[0] = "Zero";
foo[1] = "One";
foo[2] = "Two";
foo[3] = "Three";
foo(); // Alerts "Hello, World!"
alert(foo[2]); // Alerts "Two"
为什么 JavaScript 允许你这样做?这是一个故障吗?
有一天,我在编写游戏时错误地遇到了这个问题:
var foo = function() { alert("Hello, World!"); }
foo[0] = "Zero";
foo[1] = "One";
foo[2] = "Two";
foo[3] = "Three";
foo(); // Alerts "Hello, World!"
alert(foo[2]); // Alerts "Two"
为什么 JavaScript 允许你这样做?这是一个故障吗?
这里没有数组。例如,Array.isArray(foo)
是假的。
相反,您提供了foo
四个属性,名为"0"
、"1"
、"2"
和"3"
[1],具有不同的值。这是完全有效的,因为函数是对象;您始终可以使用您喜欢的任何名称将属性附加到对象。
你也可以这样做:
foo.otherProp = "hi!";
alert(foo.otherProp);
[1]:请注意,属性名称在设置之前总是转换为字符串;做foo[{ toString: function () { return "baz"; }] = 5
将与foo["baz"] = 5
or相同foo.baz = 5
。同样,doingfoo[0] = "whatever"
与doing 相同foo["0"] = "whatever"
。
为什么 JavaScript 允许您将数组和函数存储在一个变量中?
它没有。它允许您将对函数的引用存储在变量中。函数是 JavaScript 中的一等对象,因此它们可以具有属性,包括具有 、 等名称的"0"
属性"1"
。
您在这里看到了几件事:
我上面说过,函数是对象,所以你可以给它们添加属性。
您可以临时添加属性,无需像在某些其他语言中那样预定义它们。
在 JavaScript 中,您可以使用点表示法和文字 ( foo.bar)
,或者使用括号表示法和字符串 ( foo["bar"]
) 来引用属性。
当你使用方括号表示法时,如果括号内的东西还不是一个字符串,那么它实际上是一个字符串,所以[0]
实际上是["0"]
.
是的,即使在处理数组时也是如此,因为JavaScript 中的标准数组并不是真正的数组。(有最近添加的,Int32Array
等等,它们是真正的数组,但Array
不是。)
答案很简单,可以用三段论来表达(我觉得好玩)。
所有对象都可以具有开发人员定义的属性1。
所有函数都是对象。
因此,所有函数都可以具有开发人员定义的属性。
1从技术上讲,并非所有对象。“强化”对象不能被不受信任的代码改变,嵌入 JavaScript 运行时的应用程序提供的对象可以自定义它们的行为以防止这种情况发生。不过,这些都是边缘情况。在 JavaScript 运行时中创建的未强化对象都应该具有此功能,并且大多数时候这些对象都是试图改变的对象。
foo[0]
在这种情况下,将值分配给名为“0”的属性。函数是一个对象,可以为其添加属性。
同样,这两个是等价的:
foo["abc"]
foo.abc
到目前为止没有人提到的是,此功能允许您将信息与可能对该功能有用的功能相关联,但不会用大量可能造成冲突等的公共数据污染全局空间。
这当然是一般的 OOP/原型设计的一个特性,但它还有一个额外的好处,就是让您可以直接调用函数,而不是作为更通用对象的属性。
Javascript 中几乎所有的东西(包括函数)都是一个对象,所以你可以给它额外的属性,比如0
和1
。
首先,您的问题与您的标题无关。
在你的标题中提出的问题的答案是,“为什么 JavaScript 允许你在一个变量中存储一个数组和一个函数?”,JavaScript 是一种动态类型语言,这意味着你可以将任何你喜欢的东西放在一个变量中,并且口译员不会抱怨。
在您的问题的正文中,您想知道为什么允许您设置函数的属性,就好像它是一个对象或数组一样。
好吧,你可以。这就是语言的定义。能够添加有关函数的元信息非常有用。
但是,是的,JavaScript 被锋利的边缘和尖尖的部分所覆盖,所以你必须小心。
在 JavaScript 中,函数是第一类对象。
function foo() {}
var isObject = foo instanceof Object;
// isObject is true
这就是将函数分配给变量,将它们作为参数传递,从函数返回它们等的处理。