Наследование и проблемы с ключевым словом "this" - PullRequest
0 голосов
/ 20 октября 2011

Я создаю довольно сложное веб-приложение, которое начинается с главного меню, в котором пользователь делает свой начальный выбор.Это первый раз, когда я пробовал настоящий ООП-подход с использованием наследования в JavaScript, и я столкнулся с первой проблемой, когда ключевое слово «this» не относится к тому, чего я ожидаю.Я предполагаю, что это является результатом более широкой проблемы с моим подходом ООП / наследования, поэтому я был бы признателен за ответ, который не только говорит мне, как решить эту отдельную проблему, но также предоставляет более глубокие отзывы и советы по моему общему подходу.

Я собираюсь опубликовать код JS только потому, что не думаю, что HTML-код является релевантным, но я, безусловно, могу опубликовать его, если это необходимо.

Следующий код определяет основной классSelect.Затем он создает подкласс Select, называемый SelectNum (посмотрите в конец кода).В SelectNum я пытаюсь переопределить метод mouseover для Select, но не полностью - я хочу сначала вызвать метод super (Select), а затем запустить некоторый дополнительный код.Но когда метод этого подкласса mouseover запускается, я немедленно получаю следующую ошибку:

"Uncaught TypeError: Невозможно вызвать метод stop из undefined"

По сути, this.shine не определено.

Для начала я использую следующий код из JavaScript О'Рейли: Полное руководство:

function inherit(p) {
   if (Object.create){ // If Object.create() is defined...
      return Object.create(p); // then just use it.
    }

   function f() {}; // Define a dummy constructor function.
   f.prototype = p; // Set its prototype property to p.
   return new f(); // Use f() to create an "heir" of p.
}

И мой код:

Select = function(el){
    return this.init(el);
}

Select.prototype = {
    init: function(el){
        var that = this;
        this.el = el;
        this.shine = el.children('.selectShine');

        el.hover(function(){
            that.mouseover();
        },function(){
            that.mouseout();
        });

        return this;
    },
    mouseover: function(){
        this.shine.stop().animate({opacity:.35},200);
    },
    mouseout: function(){
        var that = this;
        this.shine.stop().animate({opacity:.25},200);
    }
}

//Sub-classes
SelectNum = function(el){
    this.init(el);
    this.sup = inherit(Select.prototype); //allows access to super's original methods even when overwritten in this subclass
    return this;
}

SelectNum.prototype = inherit(Select.prototype);
SelectNum.prototype.mouseover = function(){
    this.sup.mouseover(); //call super's method... but this breaks down
    //do some other stuff
}

РЕДАКТИРОВАТЬ Ответ от Raynos работал.this.sup.mouseover() больше не выдает ошибку, и правильный код был запущен.Однако мне действительно нужно создать подкласс SelectNum с именем SelectLevel.В отличие от SelectNum, который переопределяет метод mouseover() своего суперкласса, SelectLevel НЕ нужно переопределять метод SelectNum mouseover():

SelectLevel = function(el){
    this.init(el);
    this.sup = inherit(SelectNum.prototype); //allows access to super's original methods even when overwritten in this subclass
    for(var k in this.sup){
        this.sup[k] = this.sup[k].bind(this);
    }
}
SelectLevel.prototype = inherit(SelectNum.prototype);

С этим кодом метод mouseover()просто вызывается непрерывно.Я полагаю, это потому, что this теперь привязан к объекту SelectLevel, поэтому this.sup в строке this.sup.mouseover() в SelectNum всегда относится к SelectNum, поэтому он просто продолжает вызывать себя.

Если я удаляю привязку this.sup[k] = this.sup[k].bind(this); в SelectLevel, я получаю ошибку Uncaught TypeError: Cannot call method 'mouseover' of undefined.Похоже, что this.sup.mouseover() вызывается непрерывно, вызывая метод mouseover для каждого объекта в цепочке прототипов.Когда он достигает Object, именно тогда возникает эта ошибка, потому что, конечно, Object не имеет свойства sup.

Кажется, что я могу решить эту проблему, удалив this.sup[k] = this.sup[k].bind(this); связывание в SelectLevel, а затем перенос this.sup.mouseover() в оператор if, который сначала проверяет свойство sup перед вызовом для него метода mouseover(): то есть if(this.sup !== undefined), но на самом деле это не такчувствую себя хорошо.

В конечном счете, я думаю, что мне не хватает чего-то фундаментального в том, как создавать подклассы в JavaScript.Хотя решения этих конкретных проблем проливают некоторый свет на то, как наследование прототипов работает в JS, я действительно думаю, что мне нужно лучшее понимание на более широком уровне.

1 Ответ

2 голосов
/ 20 октября 2011

this.sup.mouseover();

вызывает метод .mouseover для объекта this.sup.Вам нужно

this.sup.mouseover.call(this)

Вы не хотите звонить на this.sup Вы хотите позвонить на this.

Если этоболь в заднице, тогда вы можете сделать следующее в своем конструкторе

this.sup = inherit(Select.prototype);
for (var k in this.sup) {
  if (typeof this.sup[k] === "function") {
    this.sup[k] = this.sup[k].bind(this);
  }
}

Это в основном означает переопределить каждый метод с той же функцией, но жестко привязать значение this к тому, что вы ожидаете / хотите.*

...