Javascript:为啥是 Object.keys(someobject),而不是 someobject.keys?

Posted

技术标签:

【中文标题】Javascript:为啥是 Object.keys(someobject),而不是 someobject.keys?【英文标题】:Javascript: why Object.keys(someobject), rather than someobject.keys?Javascript:为什么是 Object.keys(someobject),而不是 someobject.keys? 【发布时间】:2012-08-08 23:49:25 【问题描述】:

我经常使用以下方法获取对象键数组:

Object.keys(someobject)

我很乐意这样做。我知道 Object 是 Object 构造函数,而 keys() 是它的一种方法,并且 keys() 将返回作为第一个参数给出的任何对象的键列表。我的问题不是如何获取对象的键 - 请不要回复解释此问题的非答案。

我的问题是,为什么没有更可预测的 keys() 或 getKeys() 方法,或者 Object.prototype 上可用的 keys 实例变量,所以我可以:

someobject.keys()

或作为实例变量:

someobject.keys

然后返回键数组?

再次,我的目的是了解 javascript 的设计,以及获取密钥的有点不直观的机制的用途。我不需要帮助来获取密钥。

【问题讨论】:

【参考方案1】:

我猜你的问题的答案是“因为委员会决定如此”,但我已经听到你问“为什么?”在这句话的结尾之前。

我最近读到了这个,但我现在找不到源。归结为,在许多情况下,无论如何您都必须使用Object.prototype.keys.call(myobject),因为myobject.keys 很可能已经在对象中用于其他用途。

我想您会发现这个archived mail thread 很有趣,例如,Brendan Eich 讨论了 ECMAScript 5 中新方法的某些方面。

更新: 在挖掘mail-archive 时,我发现了this:

主题:是否应该将 Object.keys 重新定位为 Object.prototype.keys

讨论:Allen 认为这并不是真正的元层操作 因为它旨在作为替代方案用于应用层代码 到 for..in 获取可枚举属性名称的列表。作为一个 应用层方法它属于 Object.prototype 而不是 对象构造函数。原则上达成了普遍共识,但 Doug 和 Mark 务实地辩称,这太可能了 用户定义的对象将定义自己的名为“keys”的属性 这将遮蔽 Object.prototype.keys 使其无法访问 用于此类对象。

操作:将其保留为 Object.keys。

【讨论】:

【参考方案2】:

我想他们不希望Object.prototype 上有太多属性,因为您自己的属性可能会影响它们。

它们包含的越多,发生冲突的可能性就越大。


如果keysprototype 上,那么获取此对象的密钥将非常笨拙...

var myObj: 
   keys: ["j498fhfhdl89", "1084jnmzbhgi84", "jf03jbbop021gd"]
;

var keys = Object.prototype.keys.call(myObj);

一个介绍潜在阴影属性如何破坏代码的示例。

对于为什么向Object.prototype 添加新属性很重要,似乎有些困惑。

一点也不难想象存在这样的代码......

if (someObject.keys) 
    someObject.keys.push("new value")
else
    someObject.keys = ["initial value"]

很明显,如果您将keys 函数添加到Object.prototype,此代码将会中断。 someObject.keys 现在将成为一个阴影属性这一事实破坏了编写的代码以假设它不是一个阴影属性。


事后看来是 20/20

如果您想知道为什么 keys 不是原始语言的一部分,那么人们至少会习惯于围绕它进行编码......好吧,我猜他们认为没有必要,或者根本没有没想到吧。

语言中没有包含许多可能的方法和语法特性。这就是我们对规范进行修订以添加新功能的原因。例如,Array.prototype.forEach 是后期添加。但他们可以将其添加到Array.prototype,因为它不会破坏Array 的正确使用。

一种语言应该在其1.0 版本中包含所有可能的功能并不是一个现实的期望。

由于Object.keys 只是返回一个对象的可枚举属性的数组,因此这是一个非必要的添加,可以通过现有的语言特性来实现。它没有更早出现也就不足为奇了。


结论

keys 添加到Object.prototype 肯定破坏遗留代码。

在 JavaScript 这样非常流行的语言中,向后兼容性肯定是一个重要的考虑因素。此时向Object.prototype 添加新属性可能会带来灾难性的后果。

【讨论】:

+1。是的,我想那里有很多类似于您示例中的对象的 JS 代码。如果语言中的新功能强制更改遗留代码,那将非常烦人。 有人想解释一下否决票吗?请解释我的答案的哪一部分不正确。 @amnotiam ES3 或 ES5 规范没有理由不能制作“keys”或“getkeys”保留字。同样的逻辑也适用于任何其他保留字。 请注意Object 上的方法实际上并不是保留字。说Object.keys = function() alert("I broke it") 不是语法错误。您可以对原型上的方法执行相同的操作:x = hasOwnProperty : function()return false;);Object.prototype.hasOwnProperty = function () alert("Hi"); 都可以工作。 @nailer:你真的需要更仔细地阅读。我说它不是“枚举机制”。 JavaScript 已经有一种枚举键的机制。它被称为for-in。该语法枚举对象的(可枚举的)键。我已经回答了你的问题。 收集键的不直观机制(这是Object.keys所做的)源于阴影属性会导致问题的事实,因此他们不想这样做。这很简单。【参考方案3】:

您可以自己制作,但添加到Object 原型的属性越多,发生冲突的可能性就越大。这些冲突很可能会破坏任何第三方 JavaScript 库,以及任何依赖于 for...in 循环的代码。

Object.prototype.keys = function () 
    return Object.keys(this);
;

for (var key in ) 
    // now i'm getting 'keys' in here, wtf?


var something = 
    keys: 'foo'
;

something.keys(); // error

【讨论】:

这段代码破坏了 jQuery 和许多其他代码,而你没有提到它。 @Esailija 我认为碰撞警告涵盖了这一点,澄清了。 无法模拟,创建属性时指定即可:Object.defineProperty( Object.prototype, "keys", value: function(), enumerable: false) 但这是与碰撞不同的问题,无法解决。 @nailer:语言可以将它包含在Object.prototype 中,并使其不可枚举,就像它对其他属性所做的那样。这根本不是障碍(假设语言设计是考虑因素) 这里有很多误解。碰撞是指简单的阴影不便,这就是将东西放在构造函数上的原因。可枚举性是一个完全不同的问题,可以很容易地解决,就像 Object.prototype 中的其他方法一样。这个答案是错误的(因为它不是使其他库无法工作的冲突,而是可枚举性)并且没有抓住重点。

以上是关于Javascript:为啥是 Object.keys(someobject),而不是 someobject.keys?的主要内容,如果未能解决你的问题,请参考以下文章

javascript中点表示法和括号表示法之间的区别[重复]

js函数

Vue 变化检测问题

JS中key-value存取

vuejs 数据视图不更新

按自然顺序对字典键进行排序[重复]