SuperDisk
SuperDisk

Reputation: 2840

JavaScript: Setting variable to new function on created object, it still calls old function

I've got a "class" that looks like this:

export function IBXMReplay() {
    var onRow = function(){console.log("not right")};
    ....
}

Later on, it's called in a function like this:

var seqRow = function() {
    onRow();
    ....
}

This function is essentially called by callbacks for web audio getAudio. I construct the object like this:

var replay = new IBXMReplay();
replay.onRow = function(){console.log("Right")};

However, when onRow() is called, it always prints "not right."

What am I doing wrong??? I tried creating a setter function but that didn't work either.

Upvotes: 0

Views: 38

Answers (1)

MrFusion
MrFusion

Reputation: 911

The problem is that the onRow function is being defined as a variable in the IBXMReplay local scope, and i'm assuming that the seqRow function is also inside IBXMReplay. Local-scope variables cannot be directly accessed nor modified from the outside.

For this to work, you'd need to make the onRow function a property of the IBXMReplay object (in JS functions are objects too):

export function IBXMReplay() {
    this.onRow = function(){console.log("not right")};
    ....
}

Or better yet, store it in the prototype:

var IBXMReplay = function IBXMReplay() {
    ....
}
IBXMReplay.prototype.onRow = function(){console.log("not right")};
export IBXMReplay

Either way, you can later do:

var replay = new IBXMReplay();
replay.onRow = function(){console.log("Right")};

It should work as you expected.


Now, some explanation about that. Let's say you have 100 instances of the IBXMReplay 'class'. The differences between storing it as an object property vs. a prototype property are subtle but important:

Object property

Storing the method like this.onRow will mean there'll be 100 copies of it in memory. If you later edit it with replay.onRow = something, it'll be completely replaced for that particular instance.

Doing something like delete replay.onRow would not bring the original function back and will instead throw an 'undefined is not a function' error when executing that instance..

Prototype property

Storing the function in the object's prototype instead will mean there'll only be a single copy of onRow being referenced by all instances. When editing the instance with replay.onRow = something, the underlying prototype onRow is merely being shadowed by an object property with the same name, so any calls inside the IBXMReplay class will reference the overriding function instead.

Deleting the instance property delete replay.onRow will 'uncover' the original function.

This is how JavaScript works, and is called the prototype chain. Whenever you do foo.bar, a bar property is searched directly in the foo object, but if not found then it's searched in foo's prototype, and then the prototype's prototype, and so on, until reaching null, which has no prototype.

Upvotes: 1

Related Questions