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

Javascript子类、超级构造函数和使用自定义扩展基类方法,javascript,javascript-objects,javascript-inheritance,Javascript,Javascript Objects,Javascript Inheritance,在另一个关于是调用超级构造函数还是使用原型链的问题中,其中一个用户提供的答案似乎是合理的,但当我在具有多层继承的解决方案上实现它时,它并不适用于我 以下是我所指的答案: 因此,我使用这个自定义扩展方法创建了一个JSFIDLE来说明这个问题: 我在底部添加了JSFIDLE代码 在我的测试中,我创建了一个从基类到子类的4层类继承结构,每个子类(基类除外)都使用“extend”方法从前面的子类继承。当您点击test按钮时,我正在打印class.baseClassMethod以查看它是否找到它,但它只为

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

以下是我所指的答案:

因此,我使用这个自定义扩展方法创建了一个JSFIDLE来说明这个问题:
我在底部添加了JSFIDLE代码

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

您应该看到以下结果: 函数(){this.output+=“baseClassMethod”;}
未定义
未定义
未定义

原因是否可能是对超级构造函数的调用干扰了“this”上下文?

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

});
函数扩展(基类,子类){
var originalPrototype=子类.prototype;
subClass.prototype=Object.create(baseClass.prototype);
for(原始原型中的var键){
subClass.prototype[key]=原始原型[key];
}
subClass.prototype.constructor=子类;
Object.defineProperty(subClass.prototype,“构造函数”{
可枚举:false,
值:子类
});
};
var baseClass=函数(){
this.output=“Base:”;
this.toggleWizardHandlers=[];
this.baseClassMethod=函数(){
this.output+=“baseClassMethod”;
};
};
baseClass.prototype.on=函数(eventName,处理程序){
开关(eventName.toLowerCase()){
案例“切换向导”:
返回此.toggleWizardHandlers.push(处理程序);
打破
}
};
baseClass.prototype.toggleWizards=函数(newWizard,newStepIndex){
变量处理程序,i,len,ref;
ref=this.toggleWizardHandlers;
对于(变量i=0;i“+消息);
};
this.clearLog=函数(){
$(“#log”).html(“”);
};
this.testBaseClass=新的基类();
this.testSubClass=新的子类();
this.testSubSubClass=新的subSubClass();
this.TestSubSubClass=新的SubSubClass();
//test.on(“toggleWizards”,function(param){that.log(param);});
};
$(函数(){
var manage=新经理(“”);
$(“#btn”)。单击(函数(){
manage.log(“启动测试”);
manage.clearLog();
试一试{
manage.log(manage.testBaseClass.baseClassMethod);
}捕获(e){
管理日志(e);
}
试一试{
manage.log(manage.testSubClass.baseClassMethod);
}捕获(e){
管理日志(e);
}
试一试{
log(manage.testsubclass.baseClassMethod);
}捕获(e){
管理日志(e);
}
试一试{
log(manage.testsubclass.baseClassMethod);
}捕获(e){
管理日志(e);
}
});
});

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

var subClass = function() {
    baseClass.apply(this);
};
否则,子类new
对象将作为第一个参数传递给超级构造函数,
将引用全局对象(或在严格模式下为null)


一件小事情,将构造函数函数大写是很常见的,这样就可以清楚地看到它们应该用
new
调用,而不是作为常规函数调用。

当调用超级构造函数时,需要使用
apply
,而不是作为简单函数调用

var subClass = function() {
    baseClass.apply(this);
};
否则,子类new
对象将作为第一个参数传递给超级构造函数,
将引用全局对象(或在严格模式下为null)


一件小事是,将构造函数函数大写是很常见的,这样就可以清楚地知道它们应该用
new
调用,而不是作为常规函数调用。

您的原型继承正在工作,您可以尝试访问
上的
或所有实例上的
切换向导

但是,构造函数中的超级调用缺少一个关键部分:。没有它,您将为第一个参数传递
this
,而不是作为
this
参数。如果没有以下内容,则基类无法初始化子类实例上的任何属性:

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

您的原型继承正在工作,您可以尝试访问所有实例上的
切换向导

但是,构造函数中的超级调用缺少一个关键部分:。没有它,您将为第一个参数传递
this
,而不是作为
this
参数。如果没有以下内容,则基类无法初始化子类实例上的任何属性:

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

复制很好,它来自
originalPrototype
而不是
基类。prototype
@mcfedr我使用这种形式的扩展,因为我在使用subClass.prototype=new baseClass()时遇到了问题,它会触发构造函数两次;我切换到subClass.prototype=Object.create(baseClass),但后来我想能够调用超级构造函数,出于某种原因,这似乎是一个很好的方法。使用Object.createObject方法,您仍然可以调用超级构造函数,访问基类属性和方法吗?这种方法缺少什么吗?您对
Object.createObject
的使用非常好。唯一的问题是您将超级构造函数作为函数调用