JavaScript:扩展 Array.prototype 有什么危险?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8859828/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JavaScript: What dangers are in extending Array.prototype?
提问by Andrey Shchekin
Google JavaScript Style Guide advises against extending the Array.prototype
.
However, I used Array.prototype.filter = Array.prototype.filter || function(...) {...}
as a way to have it (and similar methods) in browsers where they do not exist. MDN actually provides similar example.
Google JavaScript 风格指南建议不要扩展Array.prototype
. 但是,我将其用作Array.prototype.filter = Array.prototype.filter || function(...) {...}
在不存在的浏览器中使用它(和类似方法)的一种方式。MDN 实际上提供了类似的例子。
I am aware about Object.prototype
issues, but Array
is not a hash table.
我知道Object.prototype
问题,但Array
不是哈希表。
What issues may arise while extending Array.prototype
that made Google advise against it?
扩展时可能会出现哪些问题Array.prototype
,导致 Google 不建议这样做?
回答by Jamund Ferguson
Most people missed the point on this one. Polyfilling or shimming standard functionality like Array.prototype.filter
so that it works in older browsers isa good idea in my opinion. Don't listen to the haters. Mozilla even shows you how to do this on the MDN. Usually the advice for not extending Array.prototype
or other native prototypes might come down to one of these:
大多数人都忽略了这一点。在我看来,Polyfilling 或 shimming 标准功能Array.prototype.filter
使其在旧浏览器中工作是一个好主意。不要听那些仇恨者的话。Mozilla 甚至在 MDN 上向您展示了如何做到这一点。通常不扩展Array.prototype
或其他原生原型的建议可能归结为以下之一:
for..in
might not work properly- Someone else might also want to extend Array with the same function name
- It might not work properly in every browser, even with the shim.
for..in
可能无法正常工作- 其他人可能也想用相同的函数名扩展 Array
- 即使使用 shim,它也可能无法在每个浏览器中正常工作。
Here are my responses:
以下是我的回复:
- You don't need to use
for..in
on Array's usually. If you do you can usehasOwnProperty
to make sure it's legit. - Only extend natives when you know you're the only one doing it ORwhen it's standard stuff like
Array.prototype.filter
. - This is annoying and has bit me. Old IE sometimes has problems with adding this kind of functionality. You'll just have to see if it works in a case by case basis. For me the problem I had was adding
Object.keys
to IE7. It seemed to stop working under certain circumstances. Your mileage may vary.
- 您通常不需要
for..in
在 Array 上使用。如果你这样做,你可以hasOwnProperty
用来确保它是合法的。 - 只有当你知道你是唯一一个这样做的人或者当它是标准的东西时才扩展本地人,比如
Array.prototype.filter
. - 这很烦人,并且咬了我。旧 IE 有时会在添加此类功能时遇到问题。您只需要根据具体情况查看它是否有效。对我来说,我遇到的问题是添加
Object.keys
到 IE7。它似乎在某些情况下停止工作。你的旅费可能会改变。
Check out these references:
查看这些参考资料:
- http://perfectionkills.com/extending-native-builtins/
- http://blip.tv/jsconf/jsconf2011-andrew-dupont-everything-is-permitted-extending-built-ins-5211542
- https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/filter
- https://github.com/kriskowal/es5-shim
- http://perfectkills.com/extending-native-builtins/
- http://blip.tv/jsconf/jsconf2011-andrew-dupont-everything-is-permitted-extending-built-ins-5211542
- https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/filter
- https://github.com/kriskowal/es5-shim
Good luck!
祝你好运!
回答by James Sumners
I'll give you the bullet points, with key sentences, from Nicholas Zakas' excellent article Maintainable JavaScript: Don't modify objects you don't own:
我将从 Nicholas Zakas 的优秀文章可维护的 JavaScript:不要修改您不拥有的对象中给出要点和关键句子:
- Dependability: "The simple explanation is that an enterprise software product needs a consistent and dependable execution environment to be maintainable."
- Incompatible implementations: "Another peril of modifying objects that you don't own is the possibility of naming collisions and incompatible implementations."
- What if everyone did it?: "Simply put: if everyone on your team modified objects that they didn't own, you'd quickly run into naming collisions, incompatible implementations, and maintenance nightmares."
- 可靠性:“简单的解释是,企业软件产品需要一致且可靠的执行环境才能进行维护。”
- 不兼容的实现:“修改你不拥有的对象的另一个危险是命名冲突和不兼容的实现的可能性。”
- 如果每个人都这样做了呢?:“简单地说:如果你团队中的每个人都修改了他们不拥有的对象,你很快就会遇到命名冲突、不兼容的实现和维护噩梦。”
Basically, don't do it. Even if your project is never going to be used by anyone else, and you're never going to import third party code, don't do it. You'll establish a horrible habit that could be hard to break when you start trying to play nice with others.
基本上,不要这样做。即使您的项目永远不会被其他人使用,并且您永远不会导入第三方代码,也不要这样做。你会养成一个可怕的习惯,当你开始尝试与他人友好相处时,这个习惯可能很难打破。
回答by thelastshadow
As a modern update to Jamund Ferguson's answer:
作为 Jamund Ferguson 答案的现代更新:
Usually the advice for not extending Array.prototype or other native prototypes might come down to one of these:
- for..in might not work properly
- Someone else might also want to extend Array with the same function name
- It might not work properly in every browser, even with the shim.
通常不扩展 Array.prototype 或其他原生原型的建议可能归结为以下之一:
- for..in 可能无法正常工作
- 其他人可能也想用相同的函数名扩展 Array
- 即使使用 shim,它也可能无法在每个浏览器中正常工作。
Points 1. and 2. can now be mitigated in ES6by using a Symbolto add your method.
现在可以在ES6 中通过使用Symbol添加您的方法来缓解第 1. 和 2. 点。
It makes for a slightly more clumsy call structure, but adds a property that isn't iterated over and can't be easily duplicated.
它使调用结构稍显笨拙,但添加了一个不能迭代且不易复制的属性。
// 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(){ /* ... */ };
Pros:
优点:
- For..in works as expected, symbols aren't iterated over.
- No clash of method names as symbols are local to scope and take effort to retrieve.
- For..in 按预期工作,符号不会迭代。
- 没有方法名称冲突,因为符号在范围内是局部的并且需要努力检索。
Cons:
缺点:
- Only works in modern environments
- Slightly clunky syntax
- 仅适用于现代环境
- 有点笨拙的语法
回答by wadim
Prototypedoes this. It's evil. The following snippet demonstrates how doing so can produce unexpected results:
原型就是这样做的。这是邪恶的。以下代码段演示了这样做会如何产生意想不到的结果:
<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>
The result:
结果:
not only four elements function each(iterator, context) { var index = 0; . . .
and about 5000 characters more.
还有大约 5000 个字符。
回答by Raynos
Extending Array.prototype
in your own application code is safe (unless you use for .. in
on arrays, in which case you need to pay for that and have fun refactoring them).
扩展Array.prototype
您自己的应用程序代码是安全的(除非您for .. in
在数组上使用,在这种情况下您需要为此付费并享受重构它们的乐趣)。
Extending native host objects in libraries you intend others to use is not cool. You have no right to corruptthe environment of other people in your own library.
在您打算其他人使用的库中扩展本机宿主对象并不酷。您无权破坏自己图书馆中其他人的环境。
Either do this behind an optional method like lib.extendNatives()
or have [].filter
as a requirement.
做这一点的背后,如可选的方法lib.extendNatives()
还是有[].filter
作为的要求。
回答by Tikhon Jelvis
Some people use for ... in
loops to iterate through arrays. If you add a method to the prototype, the loop will also try to iterate over thatkey. Of course, you shouldn'tuse it for this, but some people do anyway.
有些人使用for ... in
循环来遍历数组。如果向原型添加方法,循环也会尝试迭代该键。当然,您不应该为此使用它,但有些人还是会这样做。
回答by test30
You can easily create somekind of sandbox with poser
library.
您可以轻松地使用poser
库创建某种沙箱。
Take a look on https://github.com/bevacqua/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))
回答by CervEd
I believe this question deserves an updated ES6answer.
我相信这个问题值得更新的ES6答案。
ES5
ES5
First of all, as many people have already stated. Extending the native prototypes to shim or polyfill new standards or fix bugs is standard practice and not harmful. For example if a browser doesn't support the .filter method if (!Array.prototype.filter)
you are free to add this functionality on your own. In-fact, the language is designed to do exactly this to manage backwards compatibility.
首先,正如许多人已经说过的那样。扩展原生原型以填充或填充新标准或修复错误是标准做法,无害。例如,如果浏览器不支持 .filter 方法,if (!Array.prototype.filter)
您可以自行添加此功能。事实上,该语言旨在做到这一点,以管理向后兼容性。
Now, you'd be forgving for thinking that since JavaScript object use prototypal inheritance, extending a native object like Array.prototype
without interfering should be easy, but up until ES6 it's not been feasible.
现在,你会原谅这样的想法,因为 JavaScript 对象使用原型继承,所以在Array.prototype
不干扰的情况下扩展原生对象应该很容易,但直到 ES6 才可行。
Unlike objects for example, you had to rely and modifying the Array.prototype
to add your own custom methods. As others have pointed out, this is badbecause it pollutes the Global namespace, can interfere with other code in an unexpected way, has potential security issues, is a cardinal sin etc.
例如,与对象不同,您必须依赖和修改Array.prototype
来添加您自己的自定义方法。正如其他人指出的那样,这很糟糕,因为它会污染 Global 命名空间,会以意想不到的方式干扰其他代码,具有潜在的安全问题,是一种大罪等。
In ES5 you can try hacking this but the implementations aren't really practically useful. For more in depth information, I recommend you check out this very informative post: http://perfectionkills.com/how-ecmascript-5-still-does-not-allow-to-subclass-an-array/
在 ES5 中,您可以尝试破解它,但这些实现实际上并没有什么用。有关更深入的信息,我建议您查看这篇内容丰富的帖子:http: //perfectkills.com/how-ecmascript-5-still-does-not-allow-to-subclass-an-array/
You can add a method to an array, or even an array constructor but you run into issues trying to work with the native array methods that rely on the length property. Worst of all, these methods are going to return a native Array.prototype
and not your shiny new sub-class array, ie: subClassArray.slice(0) instanceof subClassArray === false
.
您可以将方法添加到数组,甚至是数组构造函数,但是在尝试使用依赖于 length 属性的本机数组方法时会遇到问题。最糟糕的是,这些方法都将返回本地Array.prototype
,而不是你的闪闪发光的新子类的阵列,即:subClassArray.slice(0) instanceof subClassArray === false
。
ES6
ES6
However, now with ES6 you can subclass builtins using class
combined with extends Array
that overcomes all these issues. It leaves the Array.prototype
intact, creates a new sub-class and the array methods it inherits will be of the same sub-class! https://hacks.mozilla.org/2015/08/es6-in-depth-subclassing/
但是,现在使用 ES6,您可以使用class
withextends Array
对内置函数进行子类化,从而克服了所有这些问题。它Array.prototype
保持不变,创建一个新的子类,它继承的数组方法将属于同一个子类!https://hacks.mozilla.org/2015/08/es6-in-depth-subclassing/
See the fiddle below for a demonstration: https://jsfiddle.net/dmq8o0q4/1/
请参阅下面的小提琴演示:https: //jsfiddle.net/dmq8o0q4/1/
回答by Gershom
I want to add an additional answer that allows extending the Array
prototype without breaking for .. in
loops, and without requiring use of hasOwnPropery
:
我想添加一个额外的答案,允许在Array
不中断for .. in
循环的情况下扩展原型,并且不需要使用hasOwnPropery
:
Don't use this bad approach which causes prototype values to appear in for .. in
:
不要使用这种导致原型值出现在以下位置的糟糕方法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);
Instead use Object.defineProperty
, with enumerable: false
- it exists for pretty much exactly this reason!
而是使用Object.defineProperty
, with 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);
Note: Overall, I recommend avoiding enumerating Array
s using for .. in
. But this knowledge is still useful for extending prototypes of classes where enumeration is appropriate!
注意:总的来说,我建议避免Array
使用for .. in
. 但是这些知识对于扩展适合枚举的类的原型仍然很有用!
回答by Malvolio
Extending the prototype is a trick that only works once. You do andyou use a library that also does it (in an incompatible way) and boom!
扩展原型是一个只能使用一次的技巧。您这样做并且您使用了一个也这样做的库(以不兼容的方式)并且繁荣!