How do I emulate PHP-style __get() and __set() magic getter/setters in JavaScript? A lot of people say that this is currently impossible. I am almost certain that it is possible because projects like nowjs (http://nowjs.com) do something like this.
I know that you can utilize get and set, but these don't work when you're not sure what the property name will be. For example, what if you wanted an event handler to execute when a new property is created?
Example of what I'd want to do:
var obj = {};
notify(obj, function(key, value) {
//key is now the name of the property being set.
//value is the value of the property about to be set
console.log("setting " + key + " to " + value);
});
obj.foo = 2; //prints "setting foo to 2"
obj.bar = {a: 2}; //prints "setting bar to [Object]"
//Notice that notify() worked even though 'foo' and 'bar' weren't even defined yet!
(The question is similar to the following questions:
Is there a way to monitor changes to an object?
JavaScript getter for all properties
)
EDIT: It looks like this feature is called "dynamic proxies" and should appear in the ECMAScript "Harmony" standard (probably ES6). You can read more here. A new 'Proxy' Object is introduced with a couple methods (I.e. Create() and createFunction() ).
One could do this:
//Constructing an object proxy (proto is optional)
var proxy = Proxy.create(handler, proto);
proxy.foo = 2; //Triggers 'set' function in the handler (read about it)
Bottom line here: it doesn't work in most browsers, but an implementation is available for Node.js: node-proxy.
Looking through the nowjs source code, I believe they do this by continuously monitoring the now object and pushing changes between client and server whenever they are detected. I admit I haven't fully grokked their code yet, however.
In a browser, this would be done with some fun setInterval hacks.
EDIT: yes, that is indeed what they do: line 368 of the client now.js. They do some more tricks so that once a new property is detected, future access to it is caught by getters and setters, but those modifications are only made every 1000 ms in a setTimeout.
Another piece of evidence that this is impossible in current JavaScript is that the proxies proposal for ECMAScript Harmony is designed explicitly to enable such scenarios, implying very strongly that they can't be done currently. Recent Mozilla browsers have a prototype proxies implementation, if perhaps that's enough. And apparently V8 is working to add support, which could be enough depending on what version of V8 Node is using these days.
EDIT2: oh cool, on the server side apparently nowjs does use proxies! Which likely means they are mature enough in Node for your usage. See what they do at https://github.com/Flotype/now/blob/master/lib/proxy.js. Or just do var Proxy = require("nodejs-proxy") and hope they follow the spec so you can take advantage of the documentation from MDC and elsewhere.
In Firefox, you can use Object.watch. If you look at this thread, Object.watch() for all browsers?, there's an example of using it something like it in all browsers.
Ooops, I just realized you want to watch all properties, not a specific property... The solution above is to watch a specific property.
Perhaps this post would help...? That is however, only for specific properties and Gecko based browsers... If you need support for other browsers, its buggy, but you could look into the onpropertychange. Here's the MSDN Page. Hope that helps a bit...
Related
Is this even possible? How about other browsers? Any estimates when es6 will be "ready" and rolled out?
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
btw. https://github.com/tvcutsem/harmony-reflect Proxy does not work with current chrome (36.0.n)
You could use Object.defineProperty and Object.observe to to simulate a Proxy. I started to wonder how much functionality a polyfill could support, so I wrote an implementation (you can see it at gist.github.com/mailmindlin/640e9d707ae3bd666d70).
I was able to emulate all of the features of Proxy that didn't rely on operator overloading, whic isn't possible in JavaScript as of now.
However, you can get the get, set, and a few others working. You can use getters and setters to mirror the target object's properties:
for (var property in target)
Object.defineProperty(proxy, property, {
get: function() {
if ('get' in handler)
return handler.get(target, property, proxy);
else
return target[property];
},
set: function(value) {
if ('set' in handler)
handler.set(target, property, value, proxy);
else
target[property] = value;
}});
The only problem with that is that the getters and setters only apply to properties that were defined in for the target when the proxy was initialized, and the delete operator won't work (If you delete a property on the target object, the proxy will still enumerate it as a property; if you delete a property on the proxy, nothing will happen to the object).
To fix that, you can use Object.observe which will be called on any change to either object. A quick check on caniuse.com shows that Object.observe is available on Chrome and Opera. If you really need support for Proxy on another browser, you can poll the target and proxy objects, to check if any properties have been created or destroyed:
var oldKeys = Object.keys(proxy);
setInterval(function() {
var keys = Object.keys(proxy);
for(var i in keys)
if(!oldKeys.includes(keys[i]))
//Trigger code for a new property added
for(var i in oldKeys)
if(!keys.includes(oldKeys[i]))
//trigger code for a deleted property
oldKeys = keys;
//repeat for target object
}, 100);
If you desperately need more features of the proxy, you can try overriding methods such as Object.defineProperty and Object.getOwnPropertyDescriptor, but that might create compatibility issues with other scripts, depending on how you do it.
In short, you can do most of what you'll probably need to use Proxy for with a polyfill. As far as Google adding it to their browser, I have no idea. It apparently used to be part of the V8 engine, but it was removed because of security problems (that nobody elaborates on), as far as I could tell based on this thread.
I have created babel plugin whic allows you to do this but it comes with huge performance impact (for each property access) - it is more education example.
https://github.com/krzkaczor/babel-plugin-proxy
Here is one created by the Google Chrome team:
https://github.com/GoogleChrome/proxy-polyfill
It's not a full implementation, though.
Update: Although my answer provides a partial solution, mailmindlin's solution proves that my main point is false: you can create a polyfill for Proxy.
No, you can't. Because Proxys rely on a special (new) behavior of several language syntax elements — namely the . operator and the [index] operator — it cannot be emulated by a polyfill.
The only way do it is to change the syntax that you use. For example, if you wanted to uppercase all string properties via a proxy, you could create a "proxy" object like so:
var object = ...
var proxy = {
get: function proxyGet(key) {
var res = object[key];
if (typeof res === "string") {
res = res.toUpperCase();
}
return res;
}
}
But, then you would still have to call it differently:
proxy.get("myVar");
instead of
object.myVar;
or
proxy.myVar
which is what the new Proxy syntax supports.
Note: You could almost create a polyfill that worked only for methods, by enumerating the function properties of the object, and creating a proxy function on the proxy object for each one of these properties; however, this would not work for non-function properties, since you can't dynamically affect the way they are accessed.
So basically I would like to extend a certain type of DOM elements by the following code:
var element = document.createElement("div");
var proto = Object.create(HTMLDivElement.prototype);
proto.newMethod = function() {console.log("Good.");};
proto.newConst = Math.PI / 2;
element.__proto__ = proto;
This code works in Chrome, Firefox and IE11 (IE10 not tested, but it will probably work), but I'm not sure whether it is proper JavaScript and whether it will continue to work in the future, because anyway this code is hacking DOM elements which is partially outside JavaScript. Could someone give explanation on how it works? I don't fully understand that, and I need to know if this method is robust. Thanks.
OK, to make things clearer, I know I should use Object.create() to specify prototype, but the real problem is that element objects are special and it's impossible to do that. The above code is more like a workaround, and this is why I'm asking this question.
Google's Polymer mutates __proto__ of DOM objects (code, line 259):
function implement(element, definition) {
if (Object.__proto__) {
element.__proto__ = definition.prototype;
} else {
customMixin(element, definition.prototype, definition.native);
element.__proto__ = definition.prototype;
}
}
So, should I trust this method because Google uses it?
From Mozilla Developer Network:
The __proto__ property is deprecated and should not be used. Object.getPrototypeOf should be used instead of the __proto__ getter to determine the [[Prototype]] of an object. Mutating the [[Prototype]] of an object, no matter how this is accomplished, is strongly discouraged, because it is very slow and unavoidably slows down subsequent execution in modern JavaScript implementations. However, Object.setPrototypeOf is provided in ES6 as a very-slightly-preferred alternative to the __proto__ setter.
In general, it is a bad practice to modify native prototypes like Array, String and even HTMLElement, details are described here, but if you control everything in the current context you can modify the prototypes by adding, on your own risk, some additional functional to achieve what you want. If you can guarantee that your code is not in conflict with some other code and the performance footprint is negligible then you are free to choose your path.
Your approach:
SomeHTMLElementInstance.__proto__ = newPrototype;
// or a general case like:
SomeHTMLElementPrototypeConstructor.prototype.newMethod = function () {
// Do something here
}
Recommended approach:
var SomeElementWrapper = function (someParams) {
this.container = document.createElement('SomeHTMLElement');
}
SomeElementWrapper.prototype.someMethod = function () {
// Do something with this.container without modifying its prototype
}
RECAP:
Ok, it's been a while since I asked this question. As usual, I went and augmented the Object.prototype anyway, in spite of all the valid arguments against it given both here and elsewhere on the web. I guess I'm just that kind of stubborn jerk.
I've tried to come up with a conclusive way of preventing the new method from mucking up any expected behaviour, which proved to be a very tough, but informative thing to do. I've learned a great many things about JavaScript. Not in the least that I won't be trying anything as brash as messing with the native prototypes, (except for String.prototype.trim for IE < 9).
In this particular case, I don't use any libs, so conflicts were not my main concern. But having dug a little deeper into possible mishaps when playing around with native prototypes, I'm not likely to try this code in combination with any lib.
By looking into this prototype approach, I've come to a better understanding of the model itself. I was treating prototypes as some form of flexible traditional abstract class, making me cling on to traditional OOP thinking. This viewpoint doesn't really do the prototype model justice. Douglas Crockford wrote about this pitfall, sadly the pink background kept me from reading the full article.
I've decided to update this question in the off chance people who read this are tempted to see for themselves. All I can say to that is: by all means, do. I hope you learn a couple of neat things, as I did, before deciding to abandon this rather silly idea. A simple function might work just as well, or better even, especially in this case. After all, the real beauty of it is, that by adding just 3 lines of code, you can use that very same function to augment specific objects' prototypes all the same.
I know I'm about to ask a question that has been around for quite a while, but: Why is Object.prototype considered to be off limits? It's there, and it can be augmented all the same, like any other prototype. Why, then, shouldn't you take advantage of this. To my mind, as long as you know what you're doing, there's no reason to steer clear of the Object prototype. Take this method for example:
if (!Object.prototype.getProperties)
{
Object.prototype.getProperties = function(f)
{
"use strict";
var i,ret;
f = f || false;
ret = [];
for (i in this)
{
if (this.hasOwnProperty(i))
{
if (f === false && typeof this[i] === 'function')
{
continue;
}
ret.push(i);
}
}
return ret;
};
}
Basically, it's the same old for...in loop you would either keep safe in a function, or write over and over again. I know it will be added to all objects, and since nearly every inheritance chain in JavaScript can be traced back to the Object.prototype, but in my script, I consider it the lesser of two evils.
Perhaps, someone could do a better job at telling me where I'm wrong than this chap, among others. Whilst looking for reasons people gave NOT to touch the Object's prototype, one thing kept cropping up: it breaks the for..in loop-thingy, but then again: many frameworks do, too, not to mention your own inheritance chains. It is therefore bad practice not to include a .hasOwnProperty check when looping through an object's properties, to my mind.
I also found this rather interesting. Again: one comment is quite unequivocal: extending native prototypes is bad practice, but if the V8 people do it, who am I to say they're wrong? I know, that argument doesn't quite stack up.
The point is: I can't really see a problem with the above code. I like it, use it a lot and so far, it hasn't let me down once. I'm even thinking of attaching a couple more functions to the Object prototype. Unless somebody can tell me why I shouldn't, that is.
The fact is, it's fine as long as you know what you're doing and what the costs are. But it's a big "if". Some examples of the costs:
You'll need to do extensive testing with any library you choose to use with an environment that augments Object.prototype, because the overwhelming convention is that a blank object will have no enumerable properties. By adding an enumerable property to Object.prototype, you're making that convention false. E.g., this is quite common:
var obj = {"a": 1, "b": 2};
var name;
for (name in obj) {
console.log(name);
}
...with the overwhelming convention being that only "a" and "b" will show up, not "getProperties".
Anyone working on the code will have to be schooled in the fact that that convention (above) is not being followed.
You can mitigate the above by using Object.defineProperty (and similar) if supported, but beware that even in 2014, browsers like IE8 that don't support it properly remain in significant use (though we can hope that will change quickly now that XP is officially EOL'd). That's because using Object.defineProperty, you can add non-enumerable properties (ones that don't show up in for-in loops) and so you'll have a lot less trouble (at that point, you're primarily worried about name conflicts) — but it only works on systems that correctly implement Object.defineProperty (and a correct implementation cannot be "shimmed").
In your example, I wouldn't add getProperties to Object.prototype; I'd add it to Object and accept the object as an argument, like ES5 does for getPrototypeOf and similar.
Be aware that the Prototype library gets a lot of flak for extending Array.prototype because of how that affects for..in loops. And that's just Arrays (which you shouldn't use for..in on anyway (unless you're using the hasOwnProperty guard and quite probably String(Number(name)) === name as well).
...if the V8 people do it, who am I to say they're wrong?
On V8, you can rely on Object.defineProperty, because V8 is an entirely ES5-compliant engine.
Note that even when the properties are non-enumerable, there are issues. Years ago, Prototype (indirectly) defined a filter function on Array.prototype. And it does what you'd expect: Calls an iterator function and creates a new array based on elements the function chooses. Then ECMAScript5 came along and defined Array.prototype.filter to do much the same thing. But there's the rub: Much the same thing. In particular, the signature of the iterator functions that get called is different (ECMAScript5 includes an argument that Prototype didn't). It could have been much worse than that (and I suspect — but cannot prove — that TC39 were aware of Prototype and intentionally avoided too much conflict with it).
So: If you're going to do it, be aware of the risks and costs. The ugly, edge-case bugs you can run into as a result of trying to use off-the-shelf libraries could really cost you time...
If frameworks and libraries generally did what you are proposing, it would very soon happen that two different frameworks would define two different functionalities as the same method of Object (or Array, Number... or any of the existing object prototypes). It is therefore better to add such new functionality into its own namespace.
For example... imagine, you would have a library that would serialize objects to json and a library that would serialize them to XML and both would define their functionality as
Object.prototype.serialize = function() { ... }
and you would only be able to use the one that was defined later. So it is better if they don't do this, but instead
JSONSerializingLibrary.seralize = function(obj) { ... }
XMLSerializingLibrary.seralize = function(obj) { ... }
It could also happen that a new functionality is defined in a new ECMAscript standard, or added by a browser vendor. So imagine that your browsers would also add a serialize function. That would again cause conflict with libraries that defined the same function. Even if the libraries' functionality was the same as that which is built in to the browser, the interpreted script functions would override the native function which would, in fact, be faster.
See http://www.websanova.com/tutorials/javascript/extending-javascript-the-right-way
Which addresses some, but not all, the objections raised. The objection about different libraries creating clashing methods can be alleviated by raising an exception if a domain specific method is already present in Object.prototype. That will at least provide an alert when this undesirable event happens.
Inspired by this post I developed the following which is also available in the comments of the cited page.
!Object.implement && Object.defineProperty (Object.prototype, 'implement', {
// based on http://www.websanova.com/tutorials/javascript/extending-javascript-the-right-way
value: function (mthd, fnc, cfg) { // adds fnc to prototype under name mthd
if (typeof mthd === 'function') { // find mthd from function source
cfg = fnc, fnc = mthd;
(mthd = (fnc.toString ().match (/^function\s+([a-z$_][\w$]+)/i) || [0, ''])[1]);
}
mthd && !this.prototype[mthd] &&
Object.defineProperty (this.prototype, mthd, {configurable: !!cfg, value: fnc, enumerable: false});
}
});
Object.implement (function forEach (fnc) {
for (var key in this)
this.hasOwnProperty (key) && fnc (this[key], key, this);
});
I have used this primarily to add standard defined function on implementation that do not support them.
I'm using John Resig's recipe for JavaScript 'classes' and inheritance. I've stripped my code back to something like this for this question:
MyClass = Class.extend({
// create an <h3>Hello world!</h3> in the HTML document
init : function (divId) {
this._divId = divId;
this._textDiv = document.createElement("h3");
this._textDiv.innerHTML = "Hello world!";
document.getElementById(divId).appendChild(this._textDiv);
},
// remove the <h3> and delete this object
remove : function () {
var container = document.getElementById(this._divId);
container.parentNode.removeChild(container);
// can I put some code here to release this object?
}
});
All works well:
var widget = new MyClass("theDivId");
...
widget.remove();
I'm going to have hundreds of these things on a page (obviously with some sensible functionality) and I'd like a simple way to release the memory for each object. I understand I can use widget = null; and trust the GC releases the object when required (?), but can I do something explicit in the remove() method? I know that placing this = null; at the end of remove() doesn't work ;)
there is no ways to destroy objects manually, only way is to free all links to your object and trust removal to GC
actually in your code you should clear this._textDiv = null and container = null in remove method too, because it can be a problem for GC in some browsers
No. You don't have any way of accessing the garbage collector directly. As you say, the best you can do is make sure the object is no longer referenced.
IMO, it's better that way. The garbage collector is much smarter than you (and me) because years of research has gone into writing the thing, and even when you try and make optimisations, you're likely still not doing a better job than it would.
Of course if you're interfacing with a JS engine you will be able to control the execution and force garbage collection (among much more), although I very much doubt you're in that position. If you're interested, download and compile spider monkey (or v8, or whatever engine tickles your fancy), and in the repl I think its gc() for both.
That brings me to another point, since the standard doesn't define the internals of garbage collection, even if you manage to determine that invoking the gc at some point in your code is helpful, it's likely that that will not reap the same benefits across all platforms.
this is a keyword, to which you cannot assign any value. The only way to remove objects from a scope is to manually assign nullto every variable.
This method doesn't always work, however: In some implementations of the XMLHttpRequest, one has to reset the onreadystate and open functions, before the XMLHttpRequest object is freed from the memory.
someone asked how to get the value of a JSObject property from c. That helped me a bit.
But, does anyone know how to get the current JavaScript name of an object from c?
example:
var foo={prop:'bar'};
then somewhere for example in jsapi.cpp:
JS_somemethod(JSContext *cx, JSObject *obj){
//how do i get the name 'foo' (or the current alias) here if *obj points to the foo (or whatever alias name) object?
}
Thx for hints and answers!
Okay, just to document the question clarification from your comment I'll repeat it here:
Maybe i tell you in short my purpose: For the integration of new security system in webbrowsers i need to find out what is accessed during a common session on a website. my aim is to get something like a log which objects are accessed and how (read,write,execute). for example: window.alert (x) window.foo.bar (w) ... you now why i need the names of the variables? maybe you've got an other idea?
Just to say it up front, this is pretty tricky in general. There are a few options available to you, all of which are somewhat difficult:
Use the debugging API, either via the cool new debugger object API or via jsdbgapi.cpp (the complex and slightly gross interface that firebug uses). You can use debugger functionality to trap on all property accesses, functions calls, and local references in order to dump out interesting properties of objects.
If you're only interested in the way that your (user defined) objects are accessed, you can use Proxies that wrap your objects and dump out the accesses being performed on them. A slightly more powerful and low-level version of proxies are actually used in the browser to implement our security features. (Additionally, most of the proxy functionality is accessible for custom-created objects in the JSAPI via our meta-object-protocol, but proxies are just a much cleaner version of that same functionality.)
Instrument the interpreter loop in jsinterp.cpp. A lot of research-like work turns off the JITs and instruments the interpreter loop, because it's fairly understandable if you've worked on language implementations before. Unfortunately, it's not always easy to translate what you want to do into interpreter loop instrumentation at first, even if you have experience with language implementations.
The debugger object is definitely my favorite option of those I've listed here. If you go with that approach and end up getting stuck feel free to visit #jsapi in irc.mozilla.org and try to get a hold of jorendorff or jimb, they're a) awesome and b) the creators of the debugger object.
Without looking too closely at the API, I'm going to say that while it might be possible to do this in some very basic cases, you don't want to. This is why:
In Javascript, as in most languages, variables point to values. Variables are not the values themselves. The object is not in any way inherently related to the name foo.
For instance, you can do
var foo = {prop: 'bar'};
var fooo = foo;
var foooo = foo;
var quux = {q: foo, r: foo, s: [foo]};
All of those foos are now the exact same foo; which one do you want back? There's no API call for that because it's too ambiguous and not terribly useful.
However, if you really want to find one of the global variables holding a value, you can try iterating over the keys on the global object and testing them for the value.
for(var key in this){
if(this[key] == myval){
var myname = key;
}
}
You'd have to translate this into your API calls or else put it in a function and call that through the API.
The more simple and straightforward solution would be to figure out what you want to do with foo later on, and pass in a callback function that will do that, e.g. with JS_CallFunction.
tl;dr: Previous paragraph.