17

我想在 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显示值的人(尤其是在对象上)。更高版本的 javascript 在数组中内置了 .map 和 .filter 函数,但这些函数不会出现在for in循环中。如何创建更多不会出现在for in循环中的方法?

4

4 回答 4

24

这很简单:不要在 Arrays 中使用 for-in 循环。责备所有这样做的人 -这是一个很好的片段,可以在开发过程中告诉他们。

当然,如果一个人在泛型函数中进行枚举并且不知道他得到的是一个数组、一个普通对象还是一个具有自定义原型的对象,你可以hasOwnProperty这样使用:

for (var prop in anyObj )
    if (Object.prototype.hasOwnProperty.call(anyObj, prop))
        // do something

注意Object.prototype获取函数的显式使用 - 可能有覆盖它的对象(特别是在数据映射中,值甚至可能不是函数),不支持它的对象或不从 Object.prototype 继承的对象一点也不。另请参见此处

然而,只有意识到这个问题的脚本作者才会过滤他所有的 for-in-loops - 有些人只是因为它被推荐而这样做- 并且大部分情况下都是错误的,他应该使用 for-loop 数组迭代来代替。但我们的问题是那些不知道它的作者。

一个有趣但仅限 Mozilla 的方法是通过 覆盖数组上的枚举行为__iterate__,如此处所示

幸运的是,EcmaScript 5.1 允许我们将属性设置为不可枚举。当然,这在旧浏览器中是不支持的,但何必呢?对于所有很酷的高阶数组的东西,我们无论如何都需要使用es5-shimsdefineProperty :-)像这样使用:

Object.defineProperty(Array.prototype, "find", {
    enumerable: false,
    writable: true,
    value: function(testFun) {
        // code to find element in array
    }
});
于 2012-11-08T20:06:08.657 回答
6

根据您的限制:

// 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
    };
});

在此处阅读有关Object.defineProperty的更多信息https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperty

于 2012-11-08T19:54:13.437 回答
0

这是因为必须检查hasOwnProperty

for (var prop in arr) { 
  if (arr.hasOwnProperty(prop)) { 
    console.log(prop) 
  }
}

现在这记录了 1、2、3。

于 2012-11-08T19:38:42.253 回答
0

上面的答案漏掉了一点:

可枚举...默认为 false。( mdn )

因此,只需使用Object.defineProperty(Array.prototype, 'myFunc' myFunc)而不是就Array.prototype.myFunc = myFunc可以解决问题。

于 2019-07-02T14:21:12.633 回答