Скопируйте объект JavaScript с закрытым членом - PullRequest
1 голос
/ 14 октября 2010

Я огляделся вокруг и не нашел ничего, что могло бы мне помочь.С какой стати я не могу клонировать объект javascript с закрытыми членами, не превращая их в квантово запутанные?

Просто посмотрите на этот код ... Это обычная частная собственность с getter и setter.Так или иначе, если я вызываю открытый сеттер в одном случае, клонированный тоже меняется.Зачем?Можно ли обойти это?

obj = function(){
    var changed = 0;
    this.getChanged = function(){
        return changed;
    }
    this.setChanged = function(){
        changed = 1;
    }
    this.setUnchanged = function(){
        changed = 0;
    }
};

myObj = new obj();
copiedObj = $.extend(true, {}, myObj); // Or any other deep copy function you'd have around

myObj.setChanged();
myObj.getChanged(); // returns 1
copiedObj.getChanged(); // returns 1!
copiedObj.setUnchanged();
copiedObj.getChanged(); // returns 0
myObj.getChanged(); // returns 0

Спасибо за любые идеи.

Редактировать : Пока ничего нового.Я знаю, что в javascript нет ОО, таких как Java или C ++, но, эй, мы говорим о языках программирования, всегда есть один выход.Иногда это уродливо, но есть один.

Я понял.Решение A: просто сделайте это this.changed вместо var changes
Решение B: создайте мою собственную функцию-клон, которая заново восстанавливает весь объект

Я былпросто надеясь, что будет какое-то решение C, которое обманет javascript в стандартных объектно-ориентированных шаблонах.

Кто-то, я действительно застрял с A или B?

Ответы [ 4 ]

3 голосов
/ 14 октября 2010

Проблема в том, что изменено не является частной переменной - в JavaScript нет личных переменных. Это локальная переменная для функции, которую вы назначаете переменной obj . Когда вы создаете функции, которые присваиваются getChanged / setChanged / setUnchanged , вы создаете замыкания , которые закрываются над переменная изменилась .

Когда вы клонируете myObj , вы просто создаете дополнительные псевдонимы для этих функций. Таким образом, вы по-прежнему вызываете те же функции независимо от того, обращаетесь ли вы к ним через myObj или copiedObj , и, поскольку они являются замыканиями, вы получаете доступ к точно так же измененная переменная в обоих случаях. Поскольку вы не можете копировать функции, вам лучше не пытаться сделать измененный закрытым, а просто делать this.changed = 0; во второй строке.

1 голос
/ 14 октября 2010

Даже глубокая копия не может скопировать функцию как что-либо, кроме ссылки.А поскольку ваши функции являются замыканиями, все они имеют одни и те же частные члены.Почему бы не написать clone() метод?

1 голос
/ 14 октября 2010

Локальные переменные в функциях, которые используются как конструкторы , называются «закрытыми членами», поэтому массы Java могут понять смысл использования.Это не работает как собственность.Это локальная переменная в лексическом контексте.Это «личное» для экземпляра, а не класса.В javascript нет классов.

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

0 голосов
/ 14 октября 2010

Получил ответ.

подсказка gilly3 помогла.

Функция клонирования / глубокого копирования, которую я использовал, на самом деле была не jQuery, а A.Леви написал на похожий вопрос .

Пришлось настроить его двумя способами, чтобы работать, как я ожидал.Фактически, оригинальный автор указал путь в своем объяснении, но я не уловил его во время первого прочтения.
Сначала я создал экземпляр копии с помощью конструктора исходного объекта и
Отфильтровал функции издля в петле.

Вот результат.Надеюсь, это кому-нибудь поможет.

function clone(obj) {
    // Handle the 3 simple types, and null or undefined
    if (null == obj || "object" != typeof obj) return obj;

    // Handle Date
    if (obj instanceof Date) {
        var copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }

    // Handle Array
    if (obj instanceof Array) {
        var copy = [];
        for (var i = 0, len = obj.length; i < len; ++i) {
            copy[i] = clone(obj[i]);
        }
        return copy;
    }

    // Handle Object (functions are skipped)
    if (obj instanceof Object) {
        var copy = new obj.constructor();
        for (var attr in obj) {
            if (obj.hasOwnProperty(attr) && !(obj[attr] instanceof Function)) copy[attr] = clone(obj[attr]);
        }
        return copy;
    }

    throw new Error("Unable to copy obj! Its type isn't supported.");
}
...