Почему определение сеттера / геттера в объединении объектов .assign не работает?

1

Я пытаюсь реализовать свое наследование в моем приложении JS. Вот что я имею:

function FooObject(param1, param2) {
   this._param1= param1;
   this._param2= param2;
}

Object.defineProperties(FooObject.prototype, {
    param1:
    {
        get: function () { return this._param1; },

        set: function (val) { this._param1= val; }
    }
});

Выше - "базовый класс", хорошо?

Затем я определяю другой объект, который расширяет FooObject и добавляет больше свойств, путем слияния:

  function FooObjectA(param1, param2, param3, param4) {
    FooObject.call(this, param1, someVal);
    this._param2= param2;
    this._param3= param3;
    this._param4= param4;
  }

 FooObjectA.prototype = Object.assign(Object.create(FooObject.prototype),
 {
     constructor: FooObjectA,

    param2:
    {
        get: function () { return this._param2; },

        set: function (val) { this._param2= val; }
    },

   param3:
    {
        get: function () { return this._param3; },

        set: function (val) { this._param3 = val; }
    }

});

Теперь, если я пытаюсь получить param3, например:

  var fooInstance = new FooObjectA();

  var p = fooInstance .param3;

то p не сохраняет значение _param3, а ссылается на метод геттера.

Затем я попробовал такой подход:

  Object.defineProperties(FooObjectA.prototype, {
  {

    param2:
    {
        get: function () { return this._param2; },

        set: function (val) { this._param2= val; }
    },

   param3:
    {
        get: function () { return this._param3; },

        set: function (val) { this._param3 = val; }
    }

});

И теперь он возвращает значение из getter ok. Я новичок в JavaScript и хотел бы понять, почему это не работает, когда я помещаю getters/seters в.assign.. create..., потому что логически я не понимаю, почему эти геттеры не слиты с прототипом FooObject.

Теги:

1 ответ

1
Лучший ответ

Object.assign считывает значение свойства (вызов получателя) и сохраняет это значение на целевом объекте как простое свойство данных.

Если вы хотите скопировать определение getter/setter, вам нужно будет реализовать свою собственную функцию, которая проверяет дескриптор свойства (Object.getOwnPropertyDescriptor(obj, "propName")) и обрабатывает создание свойства getter/setter для цели.

то p не сохраняет значение _param3, а ссылается на метод геттера.

Это отдельная проблема. Вы передаете объект Object.assign ожидая, что он будет интерпретироваться как способ Object.defineProperties:

FooObjectA.prototype = smartAssign(Object.create(FooObject.prototype), {
    constructor: FooObjectA,
    param2: {
        get: function() {
            return this._param2;
        },
        set: function(val) {
            this._param2 = val;
        }
    },
    param3: {
        get: function() {
            return this._param3;
        },
        set: function(val) {
            this._param3 = val;
        }
    }
});

Если вы хотите использовать этот формат, вам нужно вызвать Object.defineProperties чтобы его интерпретировать:

FooObjectA.prototype = smartAssign(Object.defineProperties(Object.create(FooObject.prototype), {
// --------------------------------^
    constructor: FooObjectA,
    param2: {
        get: function() {
            return this._param2;
        },
        set: function(val) {
            this._param2 = val;
        }
    },
    param3: {
        get: function() {
            return this._param3;
        },
        set: function(val) {
            this._param3 = val;
        }
    }
})); // <=== Added )

Здесь приводится быстрый эскиз функции (используя синтаксис ES5), который делает это; вам нужно будет проверить и затвердеть, скорее всего:

var hasOwn = function(obj, prop) { // Paranoia, in case an object overrides it
    return Object.prototype.hasOwnProperty.call(obj, prop);
};
function smartAssign(target) {
    var n, source, key;
    for (n = 1; n < arguments.length; ++n) {
        source = arguments[n];
        for (key in source) {
            if (hasOwn(source, key)) {
                Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
            }
        }
    }
    return target;
}

Live Пример использования этого и с другой проблемой:

var hasOwn = function(obj, prop) {
    return Object.prototype.hasOwnProperty.call(obj, prop);
};
function smartAssign(target) {
    var n, source, key;
    for (n = 1; n < arguments.length; ++n) {
        source = arguments[n];
        for (key in source) {
            if (hasOwn(source, key)) {
                Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
            }
        }
    }
    return target;
}

function FooObject(param1, param2) {
    this._param1 = param1;
    this._param2 = param2;
}

Object.defineProperties(FooObject.prototype, {
    param1: {
        get: function() {
            return this._param1;
        },
        set: function(val) {
            this._param1 = val;
        }
    }
});

function FooObjectA(param1, param2, param3, param4) {
    FooObject.call(this, param1, 42);
    this._param2 = param2;
    this._param3 = param3;
    this._param4 = param4;
}

FooObjectA.prototype = smartAssign(Object.defineProperties(Object.create(FooObject.prototype), {
    constructor: FooObjectA,
    param2: {
        get: function() {
            return this._param2;
        },
        set: function(val) {
            this._param2 = val;
        }
    },
    param3: {
        get: function() {
            return this._param3;
        },
        set: function(val) {
            this._param3 = val;
        }
    }
}));

var fooInstance = new FooObjectA("p1", "p2", "p3", "p4");
console.log(fooInstance.param1);
console.log(fooInstance.param3);
  • 0
    Краткий пример решения очень приветствуется.
  • 1
    @MichaelIV: Оказалось, что была вторая проблема (которая объясняет часть вашего вопроса, которую я не сразу понял); обновлен, чтобы объяснить вторую проблему и опубликовать набросок решения первой.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню