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 plicated 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?
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 plicated 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?
Share Improve this question asked Mar 24, 2013 at 12:38 Ingo BürkIngo Bürk 20.1k7 gold badges70 silver badges103 bronze badges 5-
2
Looks like you just want
return MyClass.staticHelper(this, value );
. You cannot replacethis
, but you can return a new, similar object. – Felix Kling Commented Mar 24, 2013 at 12:41 - This will only return the new object within a call chain, but not actually replace the instance. – Ingo Bürk Commented Mar 24, 2013 at 12:41
- Yes, that's not possible. You can create a wrapper for the whole class and keep an internal reference to the actual instance though. – Felix Kling Commented Mar 24, 2013 at 12:42
- Awe, rats. Would've been nice. I'll just change my design and not overwrite the object but return them to enable call chains. For actual overwriting I can still either reassign the variable or use static functions I have for that. Thanks! – Ingo Bürk Commented Mar 24, 2013 at 12:44
- If you want to "replace" the object by making the current reference a different object, you will need to change all its properties. You can't assign to anything outside of your scope chain. – Bergi Commented Mar 24, 2013 at 13:02
4 Answers
Reset to default 2
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 plicated:
this = MyClass.staticHelper( value ); // this will fail
…because this
is not a mon 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 pletely 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 pletely 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 remend to put your methods on the prototype instead of assigning them in the constructor.
How about just returning the new instance:
function MyClass(myVar) {
// ...
this.replaceMe = function (value) {
return MyClass.staticHelper(this, value);
}
// ...
}
MyClass.staticHelper = function (instance, value) {
return new MyClass( instance.myVar += value );
}
There are two reasons why this is not going to work in Javascript.
First, despite that it looks like a variable, this
is actually a function call* and therefore cannot be assigned to. this=foo
is the same as bar()=baz
. So it's not possible to have code like this:
a = 5
a.change(10)
alert(a == 10) // nope
Second, even if this=z
were possible, that approach would fail anyways, because Javascript passes by value, therefore it's not possible to have a function that changes the value of its argument:
a = 5
change(a)
alert(a == 10) // nope
*
"is" means "fully identical in every way"
I wanted to do something very similar a while back. Unfortunately there's no way to assign a value to this
- the this
pointer is a read only variable. However the next best thing is to use a getter and setter object to change the variable holding your instance itself.
Note that this only updates a single reference to the instance. You can read more about it here: Is there a better way to simulate pointers in JavaScript?
So this is how it works:
function MyClass(pointer, myVar) {
this.myVar = myVar;
this.replaceMe = function (value) {
pointer.value = MyClass.staticHelper(this, pointer, value);
return pointer.value;
};
this.revealVar = function () {
alert(this.myVar);
};
}
MyClass.staticHelper = function (instance, pointer, value) {
return new MyClass(pointer, instance.myVar + value);
};
This is how to create the pointer
and use it:
var instance = new MyClass({
get value() { return instance; },
set value(newValue) { instance = newValue; }
}, 2);
instance.revealVar(); // alerts 2
instance.replaceMe(40).revealVar(); // alerts 42
It's not the most elegant solution but it gets the job done. You can see this code in action: http://jsfiddle/fpxXL/1/
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744379039a4571332.html
评论列表(0条)