I have seen a lot of discussion regarding extending Element. As far as I can tell, these are the main issues:
- It may conflict with other libraries
- It adds undocumented features to DOM routines
- It doesn’t work with legacy IE
- It may conflict with future changes
Given a project which references no other libraries, documents changes, and doesn’t give a damn for historical browsers:
Is there any technical reason not to extend the Element prototype. Here is an example of how this is useful:
Element.prototype.toggleAttribute=function(attribute,value) {
if(value===undefined) value=true;
if(this.hasAttribute(attribute)) this.removeAttribute(attribute);
else this.addAttribute(attribute,value);
};
I’ve seen too many comments about the evils of extending prototypes without offering a reasonable explanation.
Note 1: The above example is possibly too obvious, as toggleAttribute
is the sort of method which might be added in the future. For discussion, imagine that it’s called manngoToggleAttribute
.
Note 2: I have removed a test for whether the method already exists. Even if such a method already exists, it is more predictable to override it. In any case, I am assuming that the point here is that the method has not yet been defined, let alone implemented. That is the point here.
Is it ok? Technically yes. Should you extend native APIs? As a rule of thumb no. Unfortunately the answer is more complex. If you are writing a large framework like Ember or Angular it may be a good idea to do so because your consumers will have Benifits if better API convenience. But if you're only doing this for yourself then the rule of thumb is no.
The reasoning is that doing so destabilizes the trust of that object. In other words by adding, changing, modifying a native object it no longer follows the well understood and documented behavior that anyone else (including your future self) will expect.
This style hides implementation that can go unnoticed. What is this new method?, Is it a secret browser thing?, what does it do?, Found a bug do I report this to Google or Microsoft now?. A bit exaggerated but the point is that the truth of an API has now changed and it is unexpected in this one off case. It makes maintainability need extra thought and understanding that would not be so if you just used your own function or wrapper object. It also makes changes harder.
Relevant post: Extending builtin natives. Evil or not?
Instead of trying to muck someone else's (or standard) code just use your own.
function toggleAttribute(el, attribute, value) {
var _value = (value == null ? true : value;
if (el.hasAttribute(attribute)) {
el.removeAttribute(attribute);
} else {
el.addAttribute(attribute, _value);
}
};
Now it is safe, composible, portable, and maintainable. Plus other developers (including your future self) won't scratch their heads confused where this magical method that is not documented in any standard or JS API came from.
Do not modify objects you don't own.
Imagine a future standard defines Element.prototype.toggleAttribute
. Your code checks if it has a truthy value before assigning your function. So you could end up with the future native function, which may behave differently than what you expected.
Even more, just reading Element.prototype.toggleAttribute
might call a getter, which could run some code with undesired sideways effects. For example, see what happens when you get Element.prototype.id
.
You could skip the check and assign your function directly. But that could run a setter, with some undesired sideways effects, and your function wouldn't be assigned as the property.
You could use a property definition instead of a property assignment. That should be safer... unless Element.prototype
has some special [[DefineOwnProperty]] internal method (e.g. is a proxy).
It might fail in lots of ways. Don't do this.
In my assessment: no
Massive overwriting Element.prototype
slow down performance and can conflict with standardization, but a technical reason does not exist.
I'm using several Element.prototype custom methods. so far so good until I observe a weird behaviour.
<!DOCTYPE html >
<html >
<body>
<script>
function doThis( ){
alert('window');
}
HTMLElement.prototype.doThis = function( ){
alert('HTMLElement.prototype');
}
</script>
<button onclick="doThis( )" >Do this</button>
</body>
</html>
when button is clicked, the prototype method is executed instead of the global one. The browser seems to assume this.doThis() which is weird. To overcome, I have to use window.doThis() in the onclick.
It might be better if w3c can come with with diff syntax for calling native/custom methods e.g.
myElem.toggleAttribute() // call native method
myElem->toggleAttribute() // call custom method
Is there any technical reason not to extend the Element prototype.
Absolutely none!
pardon me: ABSOLUTELY NONE!
In addition
the .__proto__
, was practically an a illegal prototype extension until yesterday. - Today, it's a Standard.
p.s.: You should avoid the use of if(!Element.prototype.toggleAttribute)
syntax by any means, the if("toggleAttribute" in Element.prototype) will do.
来源:https://stackoverflow.com/questions/38386662/javascript-extending-element-prototype