Overwriting property in Object.observe() - javascript

I want to use Chrome's experimental Object.observe() in order to overwrite all functions being set on the object:
→ jsFiddle
var obj = {};
Object.observe(obj, function (changes) {
changes.forEach(function (data) {
if ((data.type == "new" || data.type == "updated") &&
typeof data.object[data.name] == "function" &&
typeof data.object[data.name].isWrapper == "undefined") {
data.object[data.name] = function () {
};
data.object[data.name].isWrapper = true;
}
});
});
obj.helloWorld = function () {
console.log("helloWorld() was called");
};
obj.helloWorld();
Unfortunately, the console still displays "helloWorld() was called". Is it actually possible to overwrite the currently changed value in an object observer?
Since this is only an experiment (no production code!), I appreciate any kind of solution.

Well, you cannot really solve the problem at hand.
While you can overwrite changed values again in the observer, the observer is only executed asynchronously, unless Object.deliverChangeRecords is explicitly called, so it is only executed after obj.helloWorld() was already called in the same turn it was defined.
I updated your fiddle to show just that:
var obj = {};
function obs(changes) {
changes.forEach(function (data) {
if ((data.type == "new" || data.type == "updated") &&
typeof data.object[data.name] == "function" &&
typeof data.object[data.name].isWrapper == "undefined") {
data.object[data.name] = function () {
console.log("intercepted", data.name);
};
data.object[data.name].isWrapper = true;
}
});
}
Object.observe(obj, obs);
obj.helloWorld = function () {
console.log("helloWorld() was called");
};
// Will call the original function, as changes are not yet delivered.
obj.helloWorld();
Object.deliverChangeRecords(obs);
// Will call the intercepted function, as the changes were explicitly delivered synchronously.
obj.helloWorld();
obj.helloWorld2 = function () {
console.log("helloWorld2() was called");
};
// Will call the intercepted function, as first the changes will be delivered (end of turn) and only then the timeout callback will be called.
setTimeout(function() { obj.helloWorld2(); }, 0);
Not entirely sure if the setTimeout bits are implicitly mandated by the spec proposal or just an implementation detail, though.
Since there is no way to observe any changes immediately and synchronously without the modifying code explicitly executing Object.deliverChangeRecords, this API isn't really suited for what you're trying to achieve, at least when it comes to the current spec proposal.
A viable alternative to Object.observe might be Proxy, which is actually meant to do things like this and which IIRC is also available in Chrome (with experimental harmony features turned on).
Here is a fiddle using Proxy.

Related

Javascript scope issues when binding

I know there are sooo many similar questions on stack regarding this issue, but for the life of me I cannot understand what the problem is in my code.
Trying to level up in javascript so any advise would be helpful. I have created an object to manage slider functions.
var gMapSlider = {
mapSlideShow: false,
// why doesnt current place update when passed in
newMarker: null,
oldMarker: null,
mapSlideIn: function() {
this.contentSlide
$('#placeDetails').animate({right: '0'});
this.mapSlideShow = true;
},
mapSlideOut: function(func) {
if (typeof(func) != "function") func = function() {};
$('#placeDetails').animate({right: '-320px'}, null, null, func());
this.mapSlideShow = false;
},
mapSlideToggle: function() {
(this.mapSlideShow) ? this.mapSlideOut() : this.mapSlideIn();
},
contentSlide: function() {
if (this.newMarker) $('h1', '#placeDetails').text(this.newMarker.title);
},
mapSlide: function(marker) {
this.newMarker = marker;
if (this.oldMarker === this.newMarker) { //same marker showing
this.mapSlideToggle();
}
else if (this.oldMarker !== this.newMarker && !this.mapSlideShow) { //diff marker showing
this.contentSlide(marker);
this.mapSlideIn();
}
else if (this.oldMarker !== this.newMarker && this.mapSlideShow) {
var self = this;
console.log(self) //returns this object
this.mapSlideOut(function() {
console.log(self); // returns this object
self.contentSlide(this.newMarker);
self.mapSlideIn;
}).bind(self); // cannot read property 'bind' of undefined
}
this.oldMarker = this.newMarker;
}
}
A couple of questions
1) The problem is with my gMapSlider.mapSlide function. If I call the mapSlide function and the last else if statement applies I get a cannot read property of bind error. I have Google'd but found nothing of any real relevance. Can anyone help with what I am doing wrong here.
2) Is this the best way of managing functions within a namespace. Most code samples I see use functions in the global namespace so wanted a bit of clarification if it is advised to create objects like this in Javascript?
EDIT #torazaburo Thanks, feel like a proper Newbie, that was the issue. Put it as an answer and I will put as solved. Any advice on code architecture?
this.mapSlideOut(function() {
console.log(self); // returns this object
self.contentSlide(this.newMarker);
this.mapSlideIn;
}).bind(self);
bind() should be called on a function object but you'r calling it on the result of a function call
use this:
this.mapSlideOut.bind(self,function() {
console.log(this); // returns this object
this.contentSlide(this.newMarker);
this.mapSlideIn;
});
also the above call will return you a reference to the function with this bound to self

Checking if parameter is a contructor or an instance in javascript

I wanna do the following, if the parameter passed is a contructor, then do new 'constructor' if not, just use the instance. How can I do that?
This is what I've done so far, but it doesn't work. I think something is wrong with my code:
JS
var showList = function (view, options) {
// checking if view is a conctructor or not
if (view instanceof view) {
app.getRegion('main').show(view(options));
} else {
app.getRegion('main').show(new view(options));
}
}
so the above function can be used as:
var listView = new ListView;
showList(listView);
or straight:
showList(new ListView);
I think you're going to want to test whether the argument is an object or a function:
if (typeof view === "function")
will tell you it's a function (a constructor function in your context)
if (typeof view === "object")
will tell you that it's an already constructed object.
var showScreen = function (view, options) {
// check if view is already an object
if (typeof view === "object") {
app.getRegion('main').show(view(options));
} else {
app.getRegion('main').show(new view(options));
}
}
One thing I'm confused about in your code is if view is already an object, then why do you do view(options). That doesn't make sense to me. Doing new view(options) when view is a function makes sense, but not the other option so I think something also needs to be corrected with that line of code. Do you perhaps mean to call a method on that object?
FYI, I tend to avoid using instanceof as a general practice if there is another option because instanceof can have issues with cross frame code whereas typeof does not have those issues.
var showScreen = function (view, options) {
// checking if view is a conctructor or not
if (view instanceof Function) {
app.getRegion('main').show(new view(options));
} else {
app.getRegion('main').show(view(options));
}
}
Maybe not the best way but well.
function A(){}
var a = new A();
a instanceof A // true
a instanceof Function // false
A instanceof Function // true
This seems like a code smell to me. I think it's better pass an instance instead of a constructor function.
In this case you can do:
showScreen(new ListView(options))
If it's hard to construct a ListView you should wonder why that is.

What does "this._events || (this._events = {});" mean?

I have started learning Backbone.js. Currently my JavaScript skills are not too good. I have started to examine the backbone.js file and have come across a strange line of code whose purpose I can not figure out. Code sample (if you need more context, manually download backbone.js for developers and see line 80):
var Events = Backbone.Events = {
// Bind an event to a `callback` function. Passing `"all"` will bind
// the callback to all events fired.
on: function(name, callback, context) {
if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this;
this._events || (this._events = {});
var events = this._events[name] || (this._events[name] = []);
events.push({callback: callback, context: context, ctx: context || this});
return this;
},
What does the line this._events || (this._events = {}); mean? For me, _events looks like an inner variable, but is (this._events = {}) used for assignment or is it an or comparison? Or is || a completely different operation in this context?
It is a trick that uses javascripts "falsy" evaluation. It is the same as:
if (this._events) {
// do nothing, this._events is already defined
} else {
this._events = {};
}
The same goes for the line var events = this._events[name] || (this._events[name] = []); which could be translated to
var events;
if (this._events[name]) {
events = this._events[name];
} else {
this._events[name] = [];
events = this._events[name];
}
What line “this._events || (this._events = {});” means?
The logical OR (||) executes the first expression this._events and if falsy executes the second expression (this._events = {}).
In essence it checks if this._events is falsy and if so then assigns a new empty object to it.
That way no matter what this._events will always be at least an empty object and the code following will be able to execute without issues.
It's a way to write
if (!this._events) {
this._events = {};
}
In my opinion it's bad practice to use that kind of short hand, and I think the following line
var events = this._events[name] || (this._events[name] = []);
is even worse.
Mixing assignment, of the events with the creation of this._events[name] is quite short, but it's also hard to read. If you don't know what you're doing you might introduce subtle errors that way. That doesn't outweigh the benefits of having it all in one line.
And in the end it will be minified anyway. Let the minifiers take care of stuffing everything in one line. No need to do it yourself.

Restoring a nullified function back in JavaScript

I was simply practicing a little bit of JavaScript. My goal was to create a function that can call another function with the .invoke() until .revoke() is called, which then nullifies the function.
Later on, I've added .porcupine() which was, in theory, supposed to take the firstly invoked function (in this case, alert()) and then reapply it to the original "temp". The issue is, though, after being revoked temp becomes unknown, therefore it can not call anything anymore. Is there something very obvious to this that I'm missing out or will the solution have to be fairly messy?
var denullifier;
function revocable(unary) {
if (denullifier === null)
denullifier = unary;
return {
invoke: function(x) {
return unary(x);
},
revoke: function() {
var nullifier = unary;
unary = null;
return nullifier.apply(this, arguments);
},
porcupine: function() {
unary = denullifier;
return unary.apply(denullifier, arguments);
}
};
};
console.log('----------');
temp = revocable(alert);
temp.invoke(7); ///alerts 7
temp.revoke();
temp.porcupine(); //exception
temp.invoke(7); //doesn't get here
I don't quite understand what you're doing, but there are a few problems with your code.
if (denullifier === null)
denullifier = unary;
denullifier is not null here, it's undefined - so the condition isn't met.
return nullifier.apply(this, arguments);
You can't call alert this way, the first param must be null or window.
return unary.apply(denullifier, arguments);
The same.
This is your problem:
var denullifier;
function revocable(unary) {
if (denullifier === null)
denullifier = unary;
denullifier is undefined when declared without a value. However, you are checking for type-strict equality with null, which will be false, so denullifier is never set and porcupine is not able to restore the unary function.
I'd suggest:
Use == instead of === to get equality with undefined
Even better, use typeof denullifier != "function"
Or, (although I don't know your design) you should not make denullifier a global, static variable that will be shared amongst revocable instances, but instead make it instance-specific by putting the declaration inside the function body.

Javascript running code once

I only want my JavaScript to run once, but I cannot control how many times the javascript file is executed. Basically I'm writing a tiny JS snippet into a CMS, and the CMS is actually calling it 5-10 times. So solutions like this:
function never_called_again(args) {
// do some stuff
never_called_again = function (new_args) {
// do nothing
}
}
never_called_again();
Don't seem to work because as soon as my snippet is run again from the top the function is re-declared, and 'do some stuff' is re-evaluated. Perhaps I'm just not doing it properly, I'm not great with JS. I'm considering using something like try-catch on a global variable, something like
if (code_happened == undefined) {
\\ run code
code_happened = true;
}
EDIT: There is a consistent state e.g. if I set a variable I can see when my snippet is run again. But having to declare it before I access it, I don't know how to say 'does this variable exist yet'
Try this:
var doneTheStuff;
function whatever() {
if (!doneTheStuff) {
doneTheStuff = true;
// do the stuff
}
}
Redundant variable declarations don't affect the value of the variable. Once one of the functions has set the variable to true, the others won't do anything.
if (typeof code_happened === 'undefined') {
window.code_happened = true;
// Your code here.
}
The typeof check gets you around the fact that the global hasn't been declared. You could also just do if (!window.code_happened) since property access isn't banned for undefined properties.
Use a closure, and set a flag. If the flag is true, just return:
if ( ! window.never_called_again ) {
window.never_called_again = (function () {
var ran = false;
return function (args) {
if ( ran ) return;
ran = true;
// Do stuff
};
}());
}
Here's the fiddle: http://jsfiddle.net/U2NCs/
With jQuery, the function .one() may be useful : http://api.jquery.com/one/
W3School exemple here : http://www.w3schools.com/jquery/event_one.asp
In this way, the code is executed only once.
if(typeof onceRun == "undefined") window.onceRun=(
()=>{
//your codes...
console.log("runing...")
return true
}).call()

Categories

Resources