Эмулировать супер в javascript - PullRequest
24 голосов
/ 07 ноября 2011

По сути, есть хороший элегантный механизм для эмуляции super с синтаксисом, который прост как один из следующих

  • this.$super.prop()
  • this.$super.prop.apply(this, arguments);

Критерии для поддержки:

  1. this.$super должна быть ссылкой на прототип.т.е. если я изменю супер-прототип во время выполнения, это изменение будет отражено.Это в основном означает, что у родителя есть новое свойство, тогда это должно быть показано во время выполнения для всех дочерних элементов через super, так же как жестко закодированная ссылка на родителя будет отражать изменения,
  2. this.$super.f.apply(this, arguments); должен работать длярекурсивные вызовы.Для любого связанного набора наследования, когда по мере продвижения по цепочке наследования выполняется несколько супер-вызовов, вы не должны сталкиваться с рекурсивной проблемой.
  3. Вы не должны жестко кодировать ссылки на супер-объекты своих детей.Т.е. Base.prototype.f.apply(this, arguments); побеждает точку.
  4. Вы не должны использовать компилятор X to JavaScript или препроцессор JavaScript.
  5. Должен быть совместим с ES5

Наивная реализация будетбыть примерно таким.

var injectSuper = function (parent, child) {
  child.prototype.$super = parent.prototype;
};

Но это нарушает условие 2 .

Самый элегантный механизм, который я когда-либо видел, это IvoWetzel evalhack , который в значительной степени является препроцессором JavaScript и поэтому не соответствует критериям 4.

Ответы [ 11 ]

0 голосов
/ 07 ноября 2011

Для тех, кто не понимает проблему рекурсии, которую представляет OP, вот пример:

function A () {}
A.prototype.foo = function (n) {
    return n;
};

function B () {}
B.prototype = new A();
B.prototype.constructor = B;
B.prototype.$super = A.prototype;
B.prototype.foo = function (n) {
    if (n > 100) return -1;
    return this.$super.foo.call(this, n+1);
};

function C () {}
C.prototype = new B();
C.prototype.constructor = C;
C.prototype.$super = B.prototype;
C.prototype.foo = function (n) {
    return this.$super.foo.call(this, n+2);
};


alert(new C().foo(0)); // alerts -1, not 3

Причина: this в Javascript динамически связан

...