Javascript子类,超级构造函数和使用自定义扩展会丢失基类方法

时间:2016-02-29 09:40:08

标签: javascript javascript-objects javascript-inheritance

在另一个关于是否调用超级构造函数或使用原型链的问题中,其中一个用户提供的答案似乎合情合理,但当我在具有多个层的解决方案上实现它时,对我来说并不起作用继承。

以下是我所指的答案:https://stackoverflow.com/a/4389429/392591

所以我使用这种自定义扩展方法创建了一个jsFiddle来说明问题:https://jsfiddle.net/68q7yghv/
我在底部添加了jsFiddle代码。

在我的测试中,我创建了一个从baseClass到subSubSubClass的4层类继承结构,其中每个(baseClass除外)使用' extend'从前一个子类继承的方法。当您点击测试按钮时,我打印出 class .baseClassMethod以查看它是否找到它,但它只找到它用于基类。

您应该看到以下结果: function(){this.output + =" baseClassMethod&#34 ;; }
未定义
未定义
未定义

原因可能是对超级构造函数的调用正在弄乱'这个'背景?

function extend(baseClass, subClass) {
  var originalPrototype = subClass.prototype;
  subClass.prototype = Object.create(baseClass.prototype);
  for (var key in originalPrototype) {
    subClass.prototype[key] = originalPrototype[key];
  }
  subClass.prototype.constructor = subClass;
  Object.defineProperty(subClass.prototype, 'constructor', {
    enumerable: false,
    value: subClass
  });
};

var baseClass = function() {
  this.output = "Base: ";
  this.toggleWizardHandlers = [];
  this.baseClassMethod = function() {
    this.output += "baseClassMethod";
  };
};

baseClass.prototype.on = function(eventName, handler) {
  switch (eventName.toLowerCase()) {
    case "togglewizards":
      return this.toggleWizardHandlers.push(handler);
      break;
  }
};

baseClass.prototype.toggleWizards = function(newWizard, newStepIndex) {
  var handler, i, len, ref;
  ref = this.toggleWizardHandlers;
  for (var i = 0; i < ref.length; i++) {
    handler = ref[i];
    setTimeout(handler, 0, newWizard, newStepIndex);
  }
};

var subClass = function() {
  baseClass(this);
};
extend(baseClass, subClass);

var subSubClass = function() {
  subClass(this);
};
extend(subClass, subSubClass);

var subSubSubClass = function() {
  subSubClass(this);
};
extend(subSubClass, subSubSubClass);

var manager = function(settings) {

  this.log = function(message) {
    $("#log").html($("#log").html() + "<br />" + message);
  };
  this.clearLog = function() {
    $("#log").html("");
  };

  this.testBaseClass = new baseClass();
  this.testSubClass = new subClass();
  this.testSubSubClass = new subSubClass();
  this.testSubSubSubClass = new subSubSubClass();

  //test.on("toggleWizards", function(param) {    that.log(param);  });
};

$(function() {
  var manage = new manager("");

  $("#btn").click(function() {
    manage.log("start test");
    manage.clearLog();

    try {
      manage.log(manage.testBaseClass.baseClassMethod);
    } catch (e) {
      manage.log(e);
    }

    try {
      manage.log(manage.testSubClass.baseClassMethod);
    } catch (e) {
      manage.log(e);
    }

    try {
      manage.log(manage.testSubSubClass.baseClassMethod);
    } catch (e) {
      manage.log(e);
    }

    try {
      manage.log(manage.testSubSubSubClass.baseClassMethod);
    } catch (e) {
      manage.log(e);
    }
  });

});

2 个答案:

答案 0 :(得分:2)

您的原型继承正在运行,您可以尝试在所有实例上访问ontoggleWizards

你在构造函数中的超级调用缺乏关键部分:.call。没有它,您将传递this作为第一个参数,而不是this参数。如果没有这个,基类就无法初始化子类实例上的任何属性:

function subClass() {
    baseClass.call(this);
//            ^^^^
}

答案 1 :(得分:1)

当您调用超级构造函数时,您需要使用apply,而不是将其称为简单函数。

var subClass = function() {
    baseClass.apply(this);
};

否则,您的子类新this对象将作为超级构造函数的第一个参数传递,this将引用全局对象(或严格模式下为null)。

一个小问题,它通常用于大写构造函数,以便明确它们应该用new调用而不是常规函数。