Я пытаюсь реализовать свое наследование в моем приложении 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.
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);