Копирование методов получения / установки Javascript в другой объект-прототип - PullRequest
7 голосов
/ 18 мая 2011
// 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.Очевидно, что получатель не находит родительскую область видимости как экземпляр Sub (mySub), а скорее несуществующий экземпляр Base.

Есть ли способ обойти это, кроме необходимости назначать те же самые получатели на новый прототип

Ответы [ 4 ]

11 голосов
/ 18 мая 2011
Sub.prototype.__defineGetter__('value', Base.prototype.__lookupGetter__('value'));

Попробуйте это.

7 голосов
/ 05 января 2016

a Более современное решение состоит в использовании Object.defineProperty, поскольку он позволяет обрабатывать методы получения и установки, не нарушая их.

Единственная проблема состоит в том, что он принимает объект дескриптора, поэтому вместо того, чтобы вручную использовать один из них, используетсяObject.getOwnPropertyDescriptor функция, чтобы просто получить его для вас.

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

Object.defineProperty(Sub.prototype,'value',BazValue);
5 голосов
/ 18 мая 2011

Я думаю, что это сработает, если вы назначите

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)
2 голосов
/ 18 мая 2011

В дополнение к ответу Alex Mcp вы можете добавить новых получателей / установщиков в Sub после расширения, используя:

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