开发者

Why is it frowned upon to modify JavaScript object's prototypes?

I've come across a few comments here and there about how it's frowned upon to modify a JavaScript object's prototype? I personally don't see how it could be a problem. For instance extending the Array object to have map and include meth开发者_运维知识库ods or to create more robust Date methods?


The problem is that prototype can be modified in several places. For example one library will add map method to Array's prototype and your own code will add the same but with another purpose. So one implementation will be broken.


Mostly because of namespace collisions. I know the Prototype framework has had many problems with keeping their names different from the ones included natively.

There are two major methods of providing utilities to people..

Prototyping

Adding a function to an Object's prototype. MooTools and Prototype do this.

Advantages:

  1. Super easy access.

Disadvantages:

  1. Can use a lot of system memory. While modern browsers just fetch an instance of the property from the constructor, some older browsers store a separate instance of each property for each instance of the constructor.
  2. Not necessarily always available.

What I mean by "not available" is this:

Imagine you have a NodeList from document.getElementsByTagName and you want to iterate through them. You can't do..

document.getElementsByTagName('p').map(function () { ... });

..because it's a NodeList, not an Array. The above will give you an error something like: Uncaught TypeError: [object NodeList] doesn't have method 'map'.

I should note that there are very simple ways to convert NodeList's and other Array-like Objects into real arrays.

Collecting

Creating a brand new global variable and stock piling utilities on it. jQuery and Dojo do this.

Advantages:

  1. Always there.
  2. Low memory usage.

Disadvantages:

  1. Not placed quite as nicely.
  2. Can feel awkward to use at times.

With this method you still couldn't do..

document.getElementsByTagName('p').map(function () { ... });

..but you could do..

jQuery.map(document.getElementsByTagName('p'), function () { ... });

..but as pointed out by Matt, in usual use, you would do the above with..

jQuery('p').map(function () { ... });

Which is better?

Ultimately, it's up to you. If you're OK with the risk of being overwritten/overwriting, then I would highly recommend prototyping. It's the style I prefer and I feel that the risks are worth the results. If you're not as sure about it as me, then collecting is a fine style too. They both have advantages and disadvantages but all and all, they usually produce the same end result.


As bjornd pointed out, monkey-patching is a problem only when there are multiple libraries involved. Therefore its not a good practice to do it if you are writing reusable libraries. However, it still remains the best technique out there to iron out cross-browser compatibility issues when using host objects in javascript.

See this blog post from 2009 (or the Wayback Machine original) for a real incident when prototype.js and json2.js are used together.


There is an excellent article from Nicholas C. Zakas explaining why this practice is not something that should be in the mind of any programmer during a team or customer project (maybe you can do some tweaks for educational purpose, but not for general project use).

Maintainable JavaScript: Don’t modify objects you don’t own: https://www.nczonline.net/blog/2010/03/02/maintainable-javascript-dont-modify-objects-you-down-own/


In addition to the other answers, an even more permanent problem that can arise from modifying built-in objects is that if the non-standard change gets used on enough sites, future versions of ECMAScript will be unable to define prototype methods using the same name. See here:

This is exactly what happened with Array.prototype.flatten and Array.prototype.contains. In short, the specification was written up for those methods, their proposals got to stage 3, and then browsers started shipping it. But, in both cases, it was found that there were ancient libraries which patched the built-in Array object with their own methods with the same name as the new methods, and had different behavior; as a result, websites broke, the browsers had to back out of their implementations of the new methods, and the specification had to be edited. (The methods were renamed.)

For example, there is currently a proposal for String.prototype.replaceAll. If you ship a library which gets widely used, and that library monkeypatches a custom non-standard method onto String.prototype.replaceAll, the replaceAll name will no longer be usable by the specification-writers; it will have to be changed before browsers can implement it.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜