Google JavaScript样式指南advises against extending the Array.prototype
。
但是,我使用Array.prototype.filter = Array.prototype.filter || function(...) {...}
作为在不存在它们的浏览器中使用它(和类似方法)的方法。 MDN实际上提供了similar example。
我知道Object.prototype
问题,但Array
不是哈希表。
在延长Array.prototype
时,可能会出现哪些问题会让Google提出反对意见?
答案 0 :(得分:77)
大多数人都错过了这一点。在我看来,填充或填充Array.prototype.filter
这样的标准功能,以便它在旧版浏览器中工作 是一个好主意。不要听仇恨。 Mozilla甚至会向您展示如何在MDN上执行此操作。通常,不扩展Array.prototype
或其他原生原型的建议可能归结为其中之一:
for..in
可能无法正常工作以下是我的回复:
for..in
。如果你这样做,你可以使用hasOwnProperty
来确保它是合法的。Array.prototype.filter
这样的标准内容时才会扩展原生代。Object.keys
添加到IE7。它似乎在某些情况下停止工作。您的里程可能会有所不同。查看以下参考资料:
祝你好运!答案 1 :(得分:9)
我将从Nicholas Zakas的优秀文章Maintainable JavaScript: Don’t modify objects you don’t own中给出关键句子的要点:
基本上,不要这样做。即使您的项目永远不会被其他任何人使用,并且您永远不会导入第三方代码,也不要这样做。当你开始尝试与他人玩耍时,你会建立一种可能很难打破的可怕习惯。
答案 2 :(得分:4)
作为Jamund Ferguson答案的现代更新:
通常,不扩展Array.prototype或其他原生原型的建议可能归结为其中之一:
- for..in可能无法正常工作
- 其他人可能还想使用相同的函数名称扩展Array
- 即使使用垫片,它也可能无法在每个浏览器中正常工作。
醇>
现在可以使用ES6添加您的方法,在Symbol中缓解分数1.和2.
它使得一个稍微笨拙的调用结构,但添加了一个没有迭代的属性,并且不能轻易复制。
// Any string works but a namespace may make library code easier to debug.
var myMethod = Symbol('MyNamespace::myMethod');
Array.prototype[ myMethod ] = function(){ /* ... */ };
var arr = [];
// slightly clumsier call syntax
arr[myMethod]();
// Also works for objects
Object.prototype[ myMethod ] = function(){ /* ... */ };
优点:
缺点:
答案 3 :(得分:3)
在您自己的应用程序代码中扩展Array.prototype
是安全的(除非您在数组上使用for .. in
,在这种情况下,您需要为此付费并乐趣重构它们。)
在您希望其他人使用的库中扩展本机主机对象并不酷。您无权损坏您自己图书馆中其他人的环境。
要么在lib.extendNatives()
之类的可选方法背后执行此操作,要么将[].filter
作为要求。
答案 4 :(得分:2)
有些人使用for ... in
循环来遍历数组。如果向原型添加方法,循环也会尝试迭代那个键。当然,你不应该使用它,但有些人还是这样做。
答案 5 :(得分:2)
Prototype这样做。这是邪恶的。以下代码段演示了如何产生意外结果:
<script language="javascript" src="https://ajax.googleapis.com/ajax/libs/prototype/1.7.0.0/prototype.js"></script>
<script language="javascript">
a = ["not", "only", "four", "elements"];
for (var i in a)
document.writeln(a[i]);
</script>
结果:
not only four elements function each(iterator, context) { var index = 0; . . .
,大约5000个字符。
答案 6 :(得分:1)
您可以使用poser
库轻松创建一些沙箱。
查看https://github.com/bevacqua/poser
var Array2 = require('poser').Array();
// <- Array
Array2.prototype.eat = function () {
var r = this[0];
delete this[0];
console.log('Y U NO .shift()?');
return r;
};
var a = new Array2(3, 5, 7);
console.log(Object.keys(Array2.prototype), Object.keys(Array.prototype))
答案 7 :(得分:1)
我想添加一个额外的答案,该答案允许扩展Array
原型而不破坏for .. in
循环,并且无需使用hasOwnPropery
:
不要使用这种错误的方法,它会导致原型值出现在for .. in
中:
Array.prototype.foo = function() { return 'foo'; };
Array.prototype.bar = function() { return 'bar'; };
let a = [ 1, 2, 3, 4 ];
console.log(`Foo: ${a.foo()}`);
console.log(`Bar: ${a.bar()}`);
console.log('==== Enumerate: ====');
for (let v in a) console.log(v);
相反,将Object.defineProperty
与enumerable: false
一起使用-正是出于这个原因而存在 !
Object.defineProperty(Array.prototype, 'foo', {
value: function() { return 'foo'; },
enumerable: false
});
Object.defineProperty(Array.prototype, 'bar', {
value: function() { return 'bar'; },
enumerable: false
});
let a = [ 1, 2, 3, 4 ];
console.log(`Foo: ${a.foo()}`);
console.log(`Bar: ${a.bar()}`);
console.log('==== Enumerate: ====');
for (let v in a) console.log(v);
注意:总的来说,我建议避免使用Array
枚举for .. in
。但是,这些知识对于扩展枚举适当的类的原型仍然有用!
答案 8 :(得分:0)
扩展原型是一个只能工作一次的技巧。你使用和你也使用了一个库(以不兼容的方式)和 boom !
答案 9 :(得分:0)
您重写的功能可能被内部javascript调用使用,这可能会导致意外结果。这是指南的原因之一
例如,我覆盖了数组的indexOf函数,并且使用[]搞砸了访问数组。
答案 10 :(得分:0)
我认为这个问题值得更新 ES6 答案。
<强> ES5 强>
首先,正如许多人已经说过的那样。将原生原型扩展到垫片或填充新标准或修复错误是标准做法,并且没有害处。例如,如果浏览器不支持.filter方法if (!Array.prototype.filter)
,您可以自行添加此功能。实际上,该语言旨在实现此目的,以管理向后兼容性。
现在,您正在考虑因为JavaScript对象使用原型继承,因此扩展像Array.prototype
这样的本地对象而不会干扰应该很容易,但直到ES6它才不可行。
与对象不同,您必须依赖并修改Array.prototype
以添加自己的自定义方法。正如其他人所指出的那样,这是不好的因为它污染了全局命名空间,可能以意想不到的方式干扰其他代码,有潜在的安全问题,是一个重大的罪恶等。
在ES5中你可以尝试黑客攻击,但这些实现并没有真正有用。有关更深入的信息,我建议您查看这篇内容丰富的帖子:http://perfectionkills.com/how-ecmascript-5-still-does-not-allow-to-subclass-an-array/
您可以将方法添加到数组,甚至是数组构造函数,但是在尝试使用依赖于length属性的本机数组方法时会遇到问题。最糟糕的是,这些方法将返回原生Array.prototype
而不是您闪亮的新子类数组,即:subClassArray.slice(0) instanceof subClassArray === false
。
<强> ES6 强>
但是,现在使用ES6,您可以使用class
结合extends Array
继承内置类,从而克服所有这些问题。它保持Array.prototype
完整,创建一个新的子类,它继承的数组方法将属于同一个子类! https://hacks.mozilla.org/2015/08/es6-in-depth-subclassing/
请参阅下面的小提琴进行演示: https://jsfiddle.net/dmq8o0q4/1/