2013-03-24 3 views
5

Say У меня есть класс и некоторые статические вспомогательные методы, как это:Присвоить объект «этого»

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); 
} 

То, что я хочу сделать что-то вроде этого:

var instance = new MyClass(2); 

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

Причина заключается в том, что мой класс имеет несколько более сложную структуру, и я не хочу каждый раз назначать все внутренние переменные вручную, а скорее заменять весь объект. Есть ли простой способ сделать это?

+2

Похоже, вы просто хотите вернуть MyClass.staticHelper (this, value); '. Вы не можете заменить 'this', но вы можете вернуть новый похожий объект. –

+0

Это приведет только к возврату нового объекта в цепочку вызовов, но фактически не заменит экземпляр. –

+0

Да, это невозможно. Вы можете создать оболочку для всего класса и сохранить внутреннюю ссылку на фактический экземпляр. –

ответ

0

Как насчет возвращения нового экземпляра:

function MyClass(myVar) { 
    // ... 

    this.replaceMe = function (value) { 
     return MyClass.staticHelper(this, value); 
    } 

    // ... 
} 

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

Как упоминалось в комментариях к вопросу, это фактически не заменит экземпляр, то есть вне цепи вызова объект будет не затронут. –

+0

@ IngoBürk Я также добавил '+ =' вместо '=', чтобы он исказил свойство объекта. – 0x499602D2

+0

О, я этого не видел. Но это побеждает цель моего вопроса: моему классу требуется обновление нескольких переменных при изменении. Я искал способ не делать это вручную. –

0

Есть две причины, почему это не будет работать в JavaScript.

Во-первых, несмотря на то, что он выглядит как переменная, this на самом деле является вызовом функции * и поэтому не может быть назначен. this=foo - это то же самое, что и bar()=baz. Так что это не возможно, чтобы иметь такой код:

a = 5 
a.change(10) 
alert(a == 10) // nope 

Во-вторых, даже если this=z было возможно, что такой подход не удастся в любом случае, так как Javascript проходит по значению, поэтому не представляется возможным, чтобы иметь функцию, которая изменяет значение аргумент:

a = 5 
change(a) 
alert(a == 10) // nope 

* "является" означает "полностью идентичны во всех отношениях"

+0

Как вы думаете, 'this' будет вызов функции ??? – Bergi

+3

В спецификации не указано, что это вызов функции. [Он упоминает только «ThisBinding») (http://es5.github.com/#x10.4.3), который описывается как * «Значение, связанное с ключевым словом this this в коде ECMAScript, связанным с этим контекстом выполнения». * (http://es5.github.com/#x10.3, http://es5.github.com/#x11.1.1). –

+0

Указатель 'this' внутри функции является значением только для чтения, а не вызовом функции. Вот почему назначение 'this' не работает. –

1

instance.replaceMe(40).revealVar(); оповещения 42

ОК, для этого достаточно return MyClass.staticHelper(this, value);. Вопрос только ли следующий вызов instance.revealVar() теперь должен предупредить 2 или 42 - если вы хотите instance быть изменен на 42 она становится все более сложным:

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

... потому что this не является общей переменной, а ключевое слово и evaluates to the value of the ThisBinding of the current execution context, которое is set depending on how the function is entered - вы не можете назначить ему, вы можете установить его только при вызове функции.

Я не хочу назначать все внутренние переменные вручную каждый раз, а скорее заменять весь объект.

К сожалению, вы должны сделать так, без изменения свойств instance объекта (и закрывающего скрытого переменных) не изменит instance и revealVar() пробудет 2.

Есть ли простой способ сделать это?

Да, это может быть сделано программно.Самый простой метод будет call конструктор (снова) на текущий экземпляр, как это происходит при вызове с new keyword:

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

Тем не менее, вы не можете использовать это как статическая функция, которая создает полностью новый экземпляр. Либо вы ставите его в статическом методе, либо называете это от replaceMe с помощью this или просто положите его прямо в replaceMe.

Если вам нужен статический метод, который в первом возвращающий совершенно новый экземпляр, вы можете использовать это, а также путем копирования новых свойств на старом экземпляре:

….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; 
}; 

Это означает, что перезапись старых атрибутов, и теперь старые затворы могут собираться в мусор, поскольку ничто не относится к ним больше.

Btw, я бы рекомендовал put your methods on the prototype instead of assigning them in the constructor.

0

Я хотел сделать что-то очень похожее назад. К сожалению, нет способа присвоить значение this - указатель this является переменной только для чтения. Однако лучше всего использовать объект getter и setter для изменения переменной, содержащей ваш экземпляр.

Обратите внимание, что это обновляет только одну ссылку на экземпляр. Вы можете прочитать об этом здесь: Is there a better way to simulate pointers in JavaScript?

Так вот как это работает:

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); 
}; 

Это как создать pointer и использовать его:

var instance = new MyClass({ 
    get value() { return instance; }, 
    set value(newValue) { instance = newValue; } 
}, 2); 

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

Это не самый элегантный но он выполняет свою работу. Вы можете увидеть этот код в действии: http://jsfiddle.net/fpxXL/1/

Смежные вопросы