如何在 Array.prototype 和 Object.prototype 上的 javascript 中定义方法,使其不会出现在 for in 循环中
Posted
技术标签:
【中文标题】如何在 Array.prototype 和 Object.prototype 上的 javascript 中定义方法,使其不会出现在 for in 循环中【英文标题】:How to define method in javascript on Array.prototype and Object.prototype so that it doesn't appear in for in loop 【发布时间】:2012-10-29 01:55:42 【问题描述】:我想在 Array.prototype 和 Object.prototype 上定义辅助方法。我目前的计划是:
Array.prototype.find = function(testFun)
// code to find element in array
;
所以我可以这样做:
var arr = [1, 2, 3];
var found = arr.find(function(el) return el > 2; );
它工作正常,但如果我在 for in
循环中循环数组,则方法将显示为值:
for (var prop in arr) console.log(prop);
// prints out:
// 1
// 2
// 3
// find
这将搞砸任何其他依赖for in
来显示值的人(尤其是在对象上)。更高版本的 .map 和 .filter 函数内置在数组中,但这些函数不会出现在 for in
循环中。如何创建更多不会出现在 for in
循环中的方法?
【问题讨论】:
这就是不在数组上使用for-in循环的原因! Don't modify objects you don't own. 【参考方案1】:以上答案漏掉了一点:
可枚举 ... 默认为 false。 (mdn)
所以只需使用Object.defineProperty(Array.prototype, 'myFunc' myFunc)
而不是Array.prototype.myFunc = myFunc
即可解决问题。
【讨论】:
【参考方案2】:这很简单:不要使用for-in loops with Arrays。责备所有这样做的人 - here is a nice snippet 在开发过程中告诉他们。
当然,如果一个人在泛型函数中进行枚举,但不知道他得到的是数组、普通对象还是具有自定义原型的对象,你可以像这样使用hasOwnProperty
:
for (var prop in anyObj )
if (Object.prototype.hasOwnProperty.call(anyObj, prop))
// do something
注意显式使用 Object.prototype
来获取函数 - 可能有对象覆盖它(特别是在数据映射中,值甚至可能不是函数)、do not support it 的对象或没有的对象完全继承自 Object.prototype。另见here。
然而,只有意识到这个问题的脚本作者才会过滤他所有的 for-in-loops - 有些只是因为it gets recommended 而这样做 - 而且大部分都是错误的,他应该使用 for-loop 数组而是迭代。但我们的问题是那些不知道它的作者。
一种有趣但仅限 Mozilla 的方法是通过__iterate__
将数组上的枚举行为覆盖为demonstrated here。
幸运的是,EcmaScript 5.1 允许我们将属性设置为不可枚举。当然,这在旧浏览器中是不支持的,但何必呢?对于所有很酷的高阶数组,我们无论如何都需要使用es5-shims :-) 像这样使用defineProperty
:
Object.defineProperty(Array.prototype, "find",
enumerable: false,
writable: true,
value: function(testFun)
// code to find element in array
);
【讨论】:
我喜欢将这么长的 hasOwnProperty 放在辅助函数中。像hop(anyObj, prop)
这样的速记使我不太可能使用您提到的较短但次优的替代方案之一。
当然,您可以定义var hop = Function.prototype.call.bind(Object.prototype.hasOwnProperty)
,但由于普通程序员永远不需要它,我没有提到这一点。当然,那些提供高度通用功能的库在内部使用它。【参考方案3】:
取决于您的限制:
// In EcmaScript 5 specs and browsers that support it you can use the Object.defineProperty
// to make it not enumerable set the enumerable property to false
Object.defineProperty(Array.prototype, 'find',
enumerable: false, // this will make it not iterable
get: function(testFun)
// code to find element in array
;
);
在此处https://developer.mozilla.org/en-US/docs/javascript/Reference/Global_Objects/Object/defineProperty
了解有关 Object.defineProperty 的更多信息【讨论】:
不,你不想为这个原型方法定义一个getter函数。看看我的回答... 你不能相信任何其他人使用你的代码会做 hasOwnProperty 检查,所以这是一种安全的方法。【参考方案4】:这是因为必须检查hasOwnProperty
:
for (var prop in arr)
if (arr.hasOwnProperty(prop))
console.log(prop)
现在记录 1、2、3。
【讨论】:
bergi 试图说如果有人向 arr 或其原型添加“hasOwnProperty”属性,则此代码会中断。以上是关于如何在 Array.prototype 和 Object.prototype 上的 javascript 中定义方法,使其不会出现在 for in 循环中的主要内容,如果未能解决你的问题,请参考以下文章
实现对象的 Map 函数类似 Array.prototype.map