【问题标题】:Copying Javascript getters/setters to another prototype object将 Javascript getter/setter 复制到另一个原型对象
【发布时间】:2011-08-27 17:39:15
【问题描述】:
// 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 没有找到作为 Sub 实例 (mySub) 的父作用域,而是一个不存在的 Base 实例。

除了必须将相同的 getter 分配到新原型上之外,还有其他方法吗?

【问题讨论】:

  • 我知道这不能回答你的问题......但你为什么还需要吸气剂?这不是不必要的复杂性吗?
  • @Michael 好吧,在这个例子中,显然没有必要,我写它只是为了让我清楚地了解我面临的问题。在我的实际应用中,在获取/设置某些属性时,我需要触发其他函数和代码。

标签: javascript setter getter prototype-programming extending


【解决方案1】:

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

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

var BazValue = Object.getOwnPropertyDescriptor(Base.prototype,'value');

Object.defineProperty(Sub.prototype, 'value', BazValue);

【讨论】:

  • 这帮助我填充 MouseEvent.x: Object.defineProperty(MouseEvent.prototype, "x", Object.getOwnPropertyDescriptor(MouseEvent.prototype, "clientX"))
  • 这应该是今天公认的答案。但是 defineProperty/getOwnPropertyDescriptor 来自于 2011 年 6 月定义的 ECMAscript 5.1,在 the currently accepted answer 一个月之后
【解决方案2】:
Sub.prototype.__defineGetter__('value', Base.prototype.__lookupGetter__('value'));

试试看。

【讨论】:

  • defineGetter 是非标准的,不在 ECMA-262 标准中。有没有其他方法可以做到这一点?
  • @TylerCrompton: Object.defineProperty(Sub,'value',Object.getOwnPropertyDescriptor(Base,'value'));
【解决方案3】:

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

Sub.prototype = new Base()

问题是,当您直接从 Base.prototype.value 分配构造函数时,它永远不会运行。在您拥有 Base 类的实例之前,该值不会存在(通过 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)

【讨论】:

  • 我从来没有想过要这样继承。多么漂亮、优雅的解决方案!
  • 谢谢 :-) 让我找到出处(肯定不是我写的……)
  • 哇!这值得引起注意。很好的解决方案。
  • 这种继承形式的唯一问题是,它不是继承,而是宿命论。所有基类都在定义时(Sub.Extend(Base) 加载库时)而不是执行时(像new Sub() 那样使用库时)初始化(new superClass())。示例:Sub1.Extend(Base1)Sub2.Extend(Base2)Base1 需要 new Sub2()Base2 需要 new Sub1()。不,如果您只在初始化中运行一次,则不一定有循环。
【解决方案4】:

除了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;});

并添加到tylermwashburns 答案:您可以为此扩展函数原型:

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

【讨论】:

    猜你喜欢
    • 2013-01-08
    • 2013-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-07
    相关资源
    最近更新 更多