Javascript sub classing, super constructors and using custom extend loses base class methods

落爺英雄遲暮 提交于 2019-12-13 05:26:19

问题


In another SO question about whether to call a super-constructor or use the prototype chain the answer provided by one of the users seemed sensible but didn't work for me when I implemented it on my solution which has multiple layers of inheritance.

Here's the answer I'm referring to: https://stackoverflow.com/a/4389429/392591

So I've created a jsFiddle using this custom extend method to illustrate the problem: https://jsfiddle.net/68q7yghv/
I've added the jsFiddle code at the bottom.

In my test I've created a 4 tier class inheritance structure from baseClass through to subSubSubClass each of which (except the baseClass) use the 'extend' method to inherit from the previous sub-class. When you hit the test button I'm printing out class.baseClassMethod to see if it finds it, but it only finds it for the base class.

You should see the following results: function () { this.output += "baseClassMethod"; }
undefined
undefined
undefined

Is it possible that the cause is that the call to the super constructor is messing with the 'this' context?

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

});

回答1:


Your prototype inheritance is working, you can try to access on or toggleWizards on all your instances.

Your super calls in the constructors lack a crucial part though: .call. Without it, you are passing this for the first parameter, not as the this argument. Your base class is not able to initialise any properties on the subclass instance without this:

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



回答2:


When you call the super constructor, you need to use apply, not call it as a simple function.

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

Otherwise your sub-classes new this object is passed as the first argument to the super constructor and this will refer to the global object (or null in strict mode).

A small thing, it common to Capitalise constructor functions so that its clear that they should be called with new and not as regular functions.



来源:https://stackoverflow.com/questions/35696180/javascript-sub-classing-super-constructors-and-using-custom-extend-loses-base-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!