I'm doing some server-side javascript bits and pieces that essentially need both access to websites' full DOMs and the ability to open sites cross-domain, and at least so far, PhantomJS seems the best tool for the job.
However, it lacks an Object.watch() method, which I'd rather like to have. As such, I'm trying to use the shim posted as an answer elsewhere on Stackoverflow (available here: https://gist.github.com/384583) to give me access to just such methods.
It isn't working.
It's also well beyond my level of JavaScript understanding - so I'm wondering if anyone could help me understand both exactly what it's doing, and why it might not be working?
Thanks for the help,
Toby
(Code quoted below:
// Cross-browser object.watch and object.unwatch
// object.watch
if (!Object.prototype.watch) {
Object.prototype.watch = function (prop, handler) {
var oldval = this[prop], newval = oldval,
getter = function () {
return newval;
},
setter = function (val) {
oldval = newval;
return newval = handler.call(this, prop, oldval, val);
};
if (delete this[prop]) { // can't watch constants
if (Object.defineProperty) { // ECMAScript 5
Object.defineProperty(this, prop, {
get: getter,
set: setter,
enumerable: true,
configurable: true
});
} else if (Object.prototype.__defineGetter__ && Object.prototype.__defineSetter__) { // legacy
Object.prototype.__defineGetter__.call(this, prop, getter);
Object.prototype.__defineSetter__.call(this, prop, setter);
}
}
};
}
// object.unwatch
if (!Object.prototype.unwatch) {
Object.prototype.unwatch = function (prop) {
var val = this[prop];
delete this[prop]; // remove accessors
this[prop] = val;
};
}
And my test code:
tO = {
"v":0,
"v开发者_如何学运维plus":function(){this.v ++}
};
tO.watch("v", function(prop, oldval, newval) {
console.log("The property "+prop+" is now "+tO.v+". Newval is "+newval+" and oldval "+oldval+".");
if (newval == 5){phantom.exit()};
});
tO.v = 1;
var i = 0
for(i=0; i<10; i++) {
tO.v = i;
console.log(tO.v);
if(tO.v == 9){
console.log("got to 9");
};
};
To answer my own question: the provided shim seems to put a broken setter function in place. In particular, unless the handler function returns something meaningful (which it may well not), the property gets set to undefined. Replacing
return newval = handler.call(this, prop, oldval, val);
with
var newval = handler.call(this, prop, oldval, val) || val;
return newval;
seemed to do the job.
As a side note, this particular shim is ingenious but includes a couple of limitations:
Code relying on a watched value may take a while to work, so it's good to change watched values after critical operations if using them as flags.
You can't add multiple handlers to a value.
精彩评论