为什么.assign对象合并中的setter / getter定义不起作用?

时间:2018-05-10 09:58:39

标签: javascript

我正在尝试在我的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的值,而是引用getter方法。

然后我尝试了这种方法:

  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很陌生,想了解为什么当我把getter / setter放入.assign ...创建时,它没有用。因为从逻辑上讲,我不明白为什么那些getter没有被合并使用FooObject的原型。

1 个答案:

答案 0 :(得分:1)

Object.assign读取属性的(调用getter)并将该值作为简单数据属性存储在目标对象上。

如果要复制getter / setter定义,则需要实现自己的函数来检查属性描述符(Object.getOwnPropertyDescriptor(obj, "propName"))并处理在目标上创建getter / setter属性。

  

然后p不保存_param3的值,而是引用getter方法。

这是一个单独的问题。您正在将对象传递给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;
}

使用它的实例和修复的其他问题:

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