将 Javascript getters/setter 复制到另一个原型对象

Copying Javascript getters/setters to another prototype object

本文关键字:另一个 原型 对象 复制 setter Javascript getters      更新时间:2023-09-26
// Base class
var Base = function() {
    this._value = 'base';
};
Base.prototype = {
    constructor: Base,
    // By function
    getValue: function() {
        return this._value;
    },
    // By getter
    get value() {
        return this._value;
    }
};
// Sub class extends Base
var Sub = function() {
    this._value = 'sub';
};
Sub.prototype = {
    constructor: Sub
};
// Pass over methods
Sub.prototype.getValue = Base.prototype.getValue;
Sub.prototype.value = Base.prototype.value;
// ---
var mySub = new Sub();
alert(mySub.getValue()); // Returns 'sub'
alert(mySub.value);      // Returns 'undefined'

乍一看,mySub.value 似乎应该返回与 mySub.getValue() 相同的值,但正如你所看到的,它返回的是 undefined。显然,getter 没有找到父范围作为子实例 (mySub),而是一个不存在的基本实例。

除了必须将相同的getter分配给新原型之外,还有什么方法可以解决这个问题吗?

更现代的解决方案是使用 Object.defineProperty,因为它允许在不破坏它们的情况下处理 getter 和 setter。

唯一的问题是它需要一个描述符对象,所以不要手动创建一个,而是使用 Object.getOwnPropertyDescriptor 函数为你获取它。

var BazValue = Object.getOwnPropertyDescriptor(Base.prototype,'value');
Object.defineProperty(Sub.prototype, 'value', BazValue);
Sub.prototype.__defineGetter__('value', Base.prototype.__lookupGetter__('value'));

试试看。

我认为如果您分配它会起作用

Sub.prototype = new Base()

问题是,当您直接从 Base.prototype.value 分配构造函数时,它永远不会运行。在拥有基类的实例之前,该值将不存在(通过 new

这是我扩展Function以实现继承的典型方法:

Function.prototype.Extend = function(superClass) {
    this.prototype = new superClass();
    this.prototype.getSuperClass = function() {
        return superClass;
    };
    this.getSuperClass = this.prototype.getSuperClass;
    return this;
};

这将正确地将所有父类的方法和属性分配给子"类"。

用法如下所示

var Sub = function() {}
Sub.Extend(Base)

除了 Alex Mcp 的答案之外,您还可以在使用以下方法扩展 Sub 后向 Sub 添加新的 getter/setter:

Function.prototype.addGetter = function(val,fn){
    this.prototype.__defineGetter__(val,fn);
    return this;    
}
Function.prototype.addSetter = function(val,fn){
    this.prototype.__defineSetter__(val,fn);
    return this;    
}
//example;
Sub.Extend(Base);
Sub.addGetter('date',function(){return +new Date;});

为了补充泰勒姆沃什伯恩斯的答案:你可以为此扩展函数原型:

Function.prototype.copyGetterFrom = function(val,fromConstructor){
    this.prototype.__defineGetter__(
         val
        ,fromConstructor.prototype.__lookupGetter__(val));
    return this;   
}
//usage example.:
Sub.copyGetterFrom('value',Base);