When using ECMAScripts typeof on plugin elements (i.e. embed or object), Safari & FireFox return "function":
typeof(window.document['myPlugin']) // "function"
This can't be influenced on the plugin side, as the browser doesn't call the plugin here. Funny enough, in IE the same line evaluates to "object".
Is that simply implementation dependent behaviour as per ECMAScript §11.4.3 or am i missing something here?
The specs are all very vague when it comes to how typeof should behave with a plugin object, since ECMAScript wasn't written with plugins in mind. Hence on IE with an activex control it will tend to respond with "object" because that's how they decided to deal with it; Firefox and I believe Safari both respond with "function" because that is how they determined to deal with it.
Both answers make sense; remember that when you access the plugin with document.getElementById("myPlugin"), you aren't just getting a reference to the plugin, you're getting a reference to the HTML element that hosts the plugin, which happens to proxy calls to the plugin. Being an HTML element, it has other properties and methods that you don't even know about.
It does seem like object would make more sense in this case, but an object generally does not, cannot have a default function, and so my guess is that firefox determined to respond that it is a function() because there is no way in the NPAPI to query to see if the default function exists, short of calling InvokeDefault. while you can call a default method on an ActiveX IDispatch interface as well, it really seems more like an incidental side-effect than a design feature.
Not a terribly scientific answer, but one that might help.
Related
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, and
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.
Note 3: I see that there is now a standard method called toggleAttribute which doesn’t behave exactly the same. With modification, the above would be a simple polyfill. This doesn’t change the point of the question.
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 (Mozilla) 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.
Case: e is of type HtmlElement and not css selector
I am talking about any attribute, not just standard allowed ones, like atom-type or data-atom-type, whatever may be the name, will it work without jQuery?
I suspect $(e).attr(name,value) is too slow, first of all it is creating an entire jQuery object ($(e) !== $(e) // two objects are not same) (jsPerf: http://jsperf.com/jquery-attr-vs-native-setattribute/28) and then it invokes certain checks and then sets value, which most browsers easily support e.setAttribute.
Is there any problem replacing $(e).attr(name,value) to e.setAttribute(name,value)?
IE8 supports setAttribute as per MSDN documentation. Is there any mobile browser or any browser which will not support it?
Eventually I want to improve performance of my JavaScript framework, initially we used jQuery extensively for its cross browser DOM features.
We have now understood that unless you are using css selector, most functions such as attr,val,text are better called with their direct DOM counter part when you have instance of HtmlElement.
I suspect $(e).attr(name,value) is too slow, first of all it is creating an entire jQuery object and then it invokes certain checks and then sets value, which most browsers easily support e.setAttribute.
If you measure it, you'll find that the difference in performance is large-ish in relative terms, but miniscule in absolute terms, and it's absolute terms we normally care about. It just doesn't matter in 99.999999% of cases. If you run into a specific performance problem, and trace it to using jQuery, then consider optimizing at that point.
what is benefit of $(e).attr(name,value) vs e.setAttribute(name,value)?
In the specific case you mention, where e is an HTMLElement, there are only a couple of benefits:
There are a couple of IE-specific bugs in setAttribute that jQuery works around for you
There are some "attributes" people set when they really should be setting a property, for instance checked or disabled; jQuery maps those (this is mostly a legacy feature these days, as people should be using prop)
It does some pre-processing on boolean values for you, letting you use $(e).attr("checked", true) when true really should be "checked"
IE8 supports setAttribute as per MSDN documentation. Is there any mobile browser or any browser which will not support it?
All browsers support setAttribute. As I mention earlier, various versions of IE have had various bugs in it, but it's there and mostly works.
I've recently read that extending the DOM on the whole is bad, because of reasons listed here and here. As I understand it, the main reasons against it are:
It doesn't work very well/at all in IE
It is possible to run into conflict, such as if a framework uses Document.prototype.hide and a browser then implements a hide function on document elements
Browsers implement things in wildly different ways
However, I haven't seen anyone ask these questions.
If I wanted to extend the DOM, how would I do it safely? Besides the
obvious use of a wrapper, how would I natively add a function, such
as hide to the DOM as a whole, safely?
If it's not possible to implement it safely, what are the specific
reasons? Can I implement checks, such as checking typeof
Document.prototype.hide == 'undefined' before implementing my own
function on the prototype?
In other words, explain to me how I can extend the DOM safely and what I could do to make sure that if a browser were to make the hide function, what I could do to not make my code have to be completely reworked.
I am writing an HTML5 application that involves a lot of XML manipulation, part of this manipulation involves comparing the versions of two different XML Elements.
What I need is for every Element, Attr, and TextNode (all of which inherit from Node, AFAIK) object that gets created to have associated version information, but still be able to behave like a normal Element, Attr, or TextNode. The current working solution I am using to store the version information, is the following:
Node.prototype.MyAppAnnotation = {
Version : null
};
Now, I understand that augmenting built-in types is considered bad form, but beyond this technique, I'm at a loss for how to get the desired functionality. I don't think I can encapsulate the Node in a wrapper because I need the Node related properties and functions exposed on the wrapper. I might be able to write some sort of pass-through functions for the wrapper, but that seems really clunky.
I feel that because the app I'm writing is an HTML5 app, and as such only has to run on the most modern browsers (all of which support the augmentation of built-ins), makes this technique appropriate. Also, by providing a sufficiently obscure name to my augmentation object, I can avoid all naming collisions (except for intentional collisions). I've also explored inheritance-based solution using Google's Closure library. However, it appears that because Element, Node and TextNode don't have direct constructors (i.e. they're created off of a Document object), this technique will not work either.
I was wondering if someone could either a) recommend an elegant way of achieving this effect without augmenting Element, or b) provide a compelling reason for why I shouldn't break the "don't augment built-ins" rule in this case.
Many Thanks,
Jarabek
Your idea is theoretically valid, but there's a weird feeling I get when reading about it.
First of all - you don't have to augment any prototypes. If you just do somedomnode.myweirdname='foo' it will become a field of that object. That's what javascript does ;)
So when there is no version you'll get undefined instead of null.
But, if you want to add more functionality or wrap dom node in anything - there's a bit of history of doing that. Most of that history is dominated by stuff like jQuery :)
Just create an object that has a field containing the node. And then you can access it really simply:
myobject.node
And create the object with some constructor or just factory function:
var myobject = createDomNodeWrapper(domnode)
Other than regularly polling for changes, is there any (standard) way to register an event or callback that will be triggered any time a new property is added to a specific object?
Simply put, the answer is no.
Mozilla's JavaScript implementation has an overload for unresolvable methods, but it doesn't work for standard properties, see __noSuchMethod__. Of course, you asked for a standard method and no other implementations support this as far as I'm aware.
Once upon a time, ActionScript supported the __resolve property. As far as I know, JS has no similar crossbrowser construct, but maybe you could simulate it with some simple (but still bloaty) accessor function, like this:
http://bytes.com/topic/javascript/answers/789987-does-javascript-support-some-kind-__resolve-method