【问题标题】:Can I Write an "Extend" Inheritance Function in Javascript?我可以在 Javascript 中编写“扩展”继承函数吗?
【发布时间】:2013-03-11 12:05:57
【问题描述】:

我希望稍微简化 Javascript 中的继承。从目前收集到的资料来看,实现“类”之间“继承”的好方法如下:

function ParentClass() {
    //Parent Constructor
}

ChildClass.prototype = new ParentClass(); //Step 1: Use parent as prototype
ChildClass.prototype.constructor = ChildClass; //Step 2: Designate appropriate constructor
function ChildClass() {
    ParentClass.call(this, arguments); //Step 3: Call the parent's constructor from the child's

    //Child Constructor
}

我喜欢将流程分为三个“步骤”,如我在上面标记的(步骤 1、2 和 3)。我想将所有这三个步骤放在一个函数中(来自 Java 背景,我将其标记为“扩展”),我可以从函数构造函数对象中调用它,如下所示:

function ParentClass() {
    //Parent Constructor
}

ChildClass.extend(ParentClass); //Execute steps 1, 2 and 3 all in this function
function ChildClass() {
    //Child Constructor
}

这是我目前所拥有的:

Function.prototype.extend = function (parent) {
    var oldConstructor = this.prototype.constructor;
    this.prototype = new parent(); //Step 1
    this.prototype.constructor = function (arguments) { //Step 2
        parent.apply(this, arguments); //Step 3
        oldConstructor(arguments);
    };
}

extend 函数的第 1 步和第 2 步在这种情况下工作正常,但第 3 步给我带来了问题。我试图做的是用一个调用父构造函数的新函数替换子构造函数,然后是子构造函数。但是,当我运行它时,不会调用父构造函数。我无法确定问题(我是否正确使用了“this”关键字?);也许我以错误的方式接近这个。可以创建一个功能来做到这一点,对吧?如何制作有效的“扩展”功能?

更新:

真正的问题似乎在于我对“this”关键字的使用。这是我现在正在查看的代码:

function ParentClass(x) {
    this.value = x;
}

function ChildClass() {
}
ChildClass.extend(ParentClass);


function testtest() {
    var a = new ParentClass("hello world"); //Alerts "hello world"
    alert(a.value);
    var b = new ChildClass("hello world"); //Alerts "undefined"
    alert(b.value);
}

为什么第一个警报有效而第二个无效?我认为“this”是指函数运行的上下文,在这两种情况下都是调用构造函数(a或b)的对象。

【问题讨论】:

  • 我刚刚尝试了您的扩展功能,并且正在调用父构造函数。你能举一个不适合你的例子吗?
  • 问题似乎出在“this”关键字上。在我的父构造函数(this.x = y)中设置属性,但这些属性不适用于子对象实例。正在调用所有函数,但未按预期设置属性。

标签: javascript inheritance this


【解决方案1】:

如果你真的想这样做,也许你应该使用Coffeescript。或者至少从中获得一些想法。

它在 Javascript 之上透明地提供support for classes and inheritance,并且使用与您在此处使用的几乎相同的想法。

如果这是一项学术练习,请务必继续进行(并查看 Coffeescript 是如何为创意做的)。但除此之外,没有必要重新发明轮子。

为了直接比较,请将以下内容粘贴到http://js2coffee.org/

class Shape
  area: -> undefined
  name: -> "Shape"

class Rectangle extends Shape
  constructor: (w, h) ->
    @w = w
    @h = h

  area: ->
    @w * @h

  name: -> "Rectangle" + super

矩形的name() 现在将返回RectangleShape。名称很傻,但让您了解super 的工作原理。

它在 JS 中的样子(注意 __extends 函数中的所有管道):

var Rectangle, Shape,
  __hasProp = {}.hasOwnProperty,
  __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };

Shape = (function() {

  function Shape() {}

  Shape.prototype.area = function() {
    return void 0;
  };

  Shape.prototype.name = function() {
    return "Shape";
  };

  return Shape;

})();

Rectangle = (function(_super) {

  __extends(Rectangle, _super);

  function Rectangle(w, h) {
    this.w = w;
    this.h = h;
  }

  Rectangle.prototype.area = function() {
    return this.w * this.h;
  };

  Rectangle.prototype.name = function() {
    return "Rectangle" + Rectangle.__super__.name.apply(this, arguments);
  };

  return Rectangle;

})(Shape);

【讨论】:

  • __extends 函数似乎或多或少是我想要完成的;稍加调整,我就可以像使用自己的 extend() 函数一样使用它。谢谢!
【解决方案2】:

注意到您的第二个块中的代码不会以相同的顺序执行这些步骤。在调用extend 后声明函数时,它会覆盖extend 函数创建的构造函数。尝试先声明你的子类,然后扩展它:

这对我有用:

function Parent() {
  console.log("Parent Constructor");
}

function Child() {
  console.log("Child Constructor");
}

Child.extend(Parent);

new Child()

输出:

Parent Constructor
Child Constructor

【讨论】:

  • 无论“extend()”的顺序和函数声明如何,实际上都会调用这两个构造函数。谢谢你的帮助。我的问题措辞有误,现在我已经更新了。
猜你喜欢
  • 1970-01-01
  • 2015-11-05
  • 1970-01-01
  • 2016-08-16
  • 2011-04-21
  • 1970-01-01
  • 2013-12-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多