如何在 Array.prototype 和 Object.prototype 上的 javascript 中定义方法,使其不会出现在 for in 循环中

IT技术 javascript function
2021-01-17 04:33:50

我想在 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个回答

这很简单:不要对 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 循环数组迭代来代替。但我们的问题是那些不知道它的作者。

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

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

Object.defineProperty(Array.prototype, "find", {
    enumerable: false,
    writable: true,
    value: function(testFun) {
        // code to find element in array
    }
});
当然,您可以定义var hop = Function.prototype.call.bind(Object.prototype.hasOwnProperty),但作为普通程序员永远不需要它,我没有提到这一点。当然,那些提供高度通用功能的库在内部使用它。
2021-03-19 04:33:50
我喜欢把这么长的 hasOwnProperty 放在一个辅助函数中。像这样的速记hop(anyObj, prop)使我不太可能使用您提到的较短但次优的替代方案之一。
2021-04-01 04:33:50

根据您的限制:

// 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

不,您不想为此原型方法定义 getter 函数。看看我的回答...
2021-03-31 04:33:50
您不能相信使用您代码的其他人会进行 hasOwnProperty 检查,因此这是一种安全的方法。
2021-04-05 04:33:50

这是因为必须检查hasOwnProperty

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

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

bergi 试图说,如果有人将“hasOwnProperty”属性添加到 arr 或其原型,则此代码会中断。
2021-03-26 04:33:50

上面的答案忽略了一点:

enumerable ...默认为 false( mdn )

所以简单地使用Object.defineProperty(Array.prototype, 'myFunc' myFunc)而不是Array.prototype.myFunc = myFunc将解决问题。