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
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.
This may be too speculative a question for StackOverflow, but still.
Among all the goodness that Rx.js’s Observables are capable of, is observing changes of object properties through the ofObjectChanges method. Since the ofObjectChanges method is implemented using Object.observe, and since Object.observe is on its way out and won't make it into JavaScript spec, is it a good idea to watch for object property changes using Rx.js's ofObjectChanges? Are there any better ways of observing object’s properties?
In 2009, ECMAScript 5 added a built-in bind() function which takes an object as a parameter and returns an identical function in which this will always refer to the object you passed it. (I couldn't find anything that looked like a canonical documentation link.)
How is this different from jQuery's $.proxy() function? Did $.proxy() come first before ECMAScript 5 was released? Is there a particular reason to favor $.proxy(function(){}, this) over function(){}.bind(this)?
proxy came first and you should likely favor bind as it is a standard. The way they are called varies slightly (due to being attached to Function.prototype vs just being a function) but their behavior is the same.
There is a pretty good post here: jQuery.proxy() usage, that ends with that advice.
Edit
Please pay no attention to this post (despite being the accepted answer).
Long story short, it was my own fault for making assumptions about the context of the question, rather than just looking up the API docs, and was accepted as the answer before I could realize my own stupidity (making assumptions, without validating them) and delete it.
Matt Whipple's answer is 100% correct, and while I disagree with his statement that real Proxies are useless in JS (they would be fantastic in some low-level concerns), the rest of his statements are flat-out objectively correct (aside from actual dates for .bind vs .proxy, as .bind was in the spec years before it landed consistently in browsers).
Below is my shame, in the stocks for all to see...
Feel free to throw tomatoes at it.
If you want to know why I answered the way I did, read the comments below.
The difference between $({}).proxy() and func.bind({}) is that proxy is a loose connection.
You can detach at any time.
That's sort of what proxies are for.
The invisible-interface between what you want to do and the thing that will actually do it.
For the record, there's also a $.bind() which is not a proxy. That is to say, it fully binds to this, in the same way that func.bind() does, rather than implementing a mediator-system to attach and detach context from functions at-will.
$.proxy came first.
Below is a simple way to preserve a particular context on function call
var myProxy = (function(context,fn){
return function(){
fn.call(context);
}
})( myContext, myFn );
You could easily use this before it came out jquery.
Answer is simple:
bind is the official.
Use bind - if it really is supported in browsers which is required to run the script
From Underscore bind vs jQuery.proxy vs Native bind
In addition to what is already mentioned, there's another difference between $.proxy() and .bind. Methods bound with $.proxy will return the same reference if called multiple times; jQuery caches functions proxied to an Object.
jsFiddle
Here is a test you could try to for performance comparison.
http://jsperf.com/bind-vs-jquery-proxy/5
At this time, October 2014.
The performance varies like crazy between browsers.
IE 11 native bind is fastest.
However, for all three browsers I tested with, native bind out preform jquery proxy.
And since bind() is standard, I would suggest sticking to it if possible.
My web application uses document.createEvent and event.initEvent to create custom events of the generic type Event.
I wonder whether this is considered good practice. On the hand side, this way I can make use of the DOM event system that is already there and do not have to invent and implement my own; on the other hand this may lead to name clashes in case future standardised event models define an event type with the name I have chosen. (Or is it possible to namespace event types?)
I am asking because I have just learnt by browsing stackoverflow that putting custom properties on DOM objects or builtin Javascript objects is considered bad practise.
EDIT
I think I have found something:
http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html#events-CustomEvent
So let me rephrase my question: Am I understanding the quoted section correctly in that it is advised to actually use a CustomEvent inside a web application?
ADDED WARNING
I have just noticed that CustomEvent is not supported in Firefox versions before 6. It is supported in current Webkit-based browsers, though.
If you're going to create something and make it as namespace-proof as you can, you can do what Webkit and Mozilla do and add a name-moniker to the beginning of all of your event names. Like:
_marc_trap_door_shut
_marc_trap_door_open
_marc_trap_door_ajar
... etc ...
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 methods 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:
Super easy access.
Disadvantages:
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.
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:
Always there.
Low memory usage.
Disadvantages:
Not placed quite as nicely.
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.