Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assign object to "this"

Tags:

javascript

Say I have a class and some static helper methods like this:

function MyClass (myVar) {
    this.myVar = myVar;

    this.replaceMe = function (value) {
        // this will fail
        this = MyClass.staticHelper( value );

        return this;
    }

    this.revealVar = function () {
        alert( this.myVar );
    }
}

MyClass.staticHelper = function (instance, value) {
    return new MyClass( instance.myVar + value );
}

What I want to do is something like this:

var instance = new MyClass( 2 );

instance.revealVar(); // alerts 2
instance.replaceMe( 40 ).revealVar(); // alerts 42

The reason is that my class has a slightly more complicated structure and I don't want to assign all internal variables manually everytime, but rather replace the entire object. Is there a simple way to do so?

like image 822
Ingo Bürk Avatar asked Mar 24 '13 12:03

Ingo Bürk


People also ask

How do you assign an object to a variable?

You assign an object to such a variable by placing the object after the equal sign ( = ) in an assignment statement or initialization clause.

How do you assign an object to a reference?

You can assign an existing object reference to another variable using the Set statement without the New keyword. An assignment using Set does not copy an object. The assigned value is a reference to an object, not the object itself.

How do you assign an object in JavaScript?

assign() which is used to copy the values and properties from one or more source objects to a target object. It invokes getters and setters since it uses both [[Get]] on the source and [[Set]] on the target. It returns the target object which has properties and values copied from the target object. Object.

How do you add an object to a conditionally property?

To conditionally add a property to an object, we can make use of the && operator. In the example above, in the first property definition on obj , the first expression ( trueCondition ) is true/truthy, so the second expression is returned, and then spread into the object.


1 Answers

instance.replaceMe( 40 ).revealVar(); alerts 42

OK, for that return MyClass.staticHelper(this, value); would suffice. The question is only whether the next call to instance.revealVar() should now alert 2 or 42 - if you want instance to be changed to 42 it gets more complicated:

this = MyClass.staticHelper( value ); // this will fail

…because this is not a common variable, but a keyword and evaluates to the value of the ThisBinding of the current execution context which is set depending on how the function is entered - you cannot assign to it, you can only set it when invoking the function.

I don't want to assign all internal variables manually everytime, but rather replace the entire object.

Unfortunately you have to do so, without changing the properties of instance object (and the closure-hidden variables) you won't change the instance and revealVar() will stay 2.

Is there a simple way to do so?

Yes, it can be done programmatically. The simplest method would be to call the constructor (again) on the current instance, like it happens when invoked with the new keyword:

MyClass.call( instance, instance.myVar + value );

Yet you can't use this like the static function which creates a completely new instance. Either you put it in a static method and call that from replaceMe with this, or you just put it directly in replaceMe.

If you need a static method that at first returns a completely new instance, you could use that as well by copying the new properties on the old instance:

….replaceMe = function(val) {
    var newInst = MyClass.staticHelper(this, val); // new MyClass(this.myVar+val);
    for (var prop in newInst)
        if (newInst.hasOwnProperty(prop))
            this[prop] = newInst[prop];
    return this;
};

That means overwriting the old attributes, and also the old closures can be garbage-collected now as nothing refers to them any more.

Btw, I'd recommend to put your methods on the prototype instead of assigning them in the constructor.

like image 55
Bergi Avatar answered Oct 05 '22 16:10

Bergi