具有原型和基类的JS OO模式 [英] JS OO Pattern with Prototype and Base Class

查看:121
本文介绍了具有原型和基类的JS OO模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于OO JS来说这是一个很好的模式吗?
我正在寻找的是一种解决JavaScript继承的简单方法。

is this a good pattern for OO JS? What I am looking for is an easy way to solve inheritance in JavaScript.

function MySuperClass(arg)
{
    this.arg1 = arg;
}
function MyBaseClass(arg)
{
    this.base = MySuperClass;
    this.base(arg);
    this.arg2 = arg;
}
MyBaseClass.prototype = new MySuperClass();
function MySpecificClass(arg)
{ 
    this.base = MyBaseClass;
    this.base(arg);
    this.arg3 = arg;
}
//ensures inheritance of all properties
MySpecificClass.prototype = new MyBaseClass();

var myFirstInstance = new MySpecificClass("test");
var mySecondInstance = new MySpecificClass("test2");


推荐答案

注意:查看结束ES2015更新。

Note: See the end for an ES2015 update.

那里有几个问题。


  1. 你的 MySuperClass 函数需要一个参数,但你不能给它一个当你调用它来创建 MyBaseClass.prototype

  1. Your MySuperClass function expects an argument, but you can't give it one when you're calling it to create the MyBaseClass.prototype.

base 属性对于 MyBaseClass 中的代码将无法正常工作,因为 MyBaseClass 预计 MySuperClass ,但不是,因为 MySpecificClass 已覆盖它。

The base property you're setting on the instance won't work correctly for the code in MyBaseClass, because MyBaseClass expects that to be MySuperClass, but it isn't, because MySpecificClass has overwritten it.

这是复杂的事情。你很聪明,确定要做三代( MySuperClass MyBaseClass MySpecificClass ),因为对于两级层次结构来说这很容易实现,但对于三个+级别,它要复杂得多。 : - )

This is complex stuff. You're very smart being sure to do three generations (MySuperClass, MyBaseClass, and MySpecificClass), because it's really easy to do this for just a two-level hierarchy, but for three+ levels, it's much more complicated. :-)

如果你想在JavaScript中彻底讨论处理继承,调用超类方法等,我已经在其上写了一篇文章,以及编写了一个工具包。阅读文章并查看工具包源代码(超出了本文)可能有助于理解原型链如何工作以及如何使用工作

If you want a thorough discussion of dealing with inheritance, calling into superclass methods, etc., in JavaScript, I've written an article on it, and written a toolkit for doing it. Reading the article and looking at the toolkit source (which goes beyond the article) may be useful in understanding how the prototype chain works and how to work with it.

这是一个使用任何工具包的 not 的示例,而不是试图使超级调用变得容易。为了清楚说明,我使用了 Parent Child GrandChild 三代:

Here's an example not using any toolkit and not trying to make supercalls easy. To keep things clear, I've used the terms Parent, Child, and GrandChild for the three generations:

// A parent (base) "class"
function Parent(a) {
  this.a = a;
}
Parent.prototype.one = function() {
  console.log("I'm Parent#one: a = " + this.a);
};
Parent.prototype.two = function() {
  console.log("I'm Parent#two: a = " + this.a);
};

// A child "subclass"
function Child(a, b) {
  // Chain to "superclass" constructor
  Parent.call(this, a);

  // Do our own init
  this.b = b;
}

// Create the prototype objct that `new Child` will assign to instances
// by creating a blank object backed by `Parent.prototype`. Also set
// the `constructor` property on the object; JavaScript defines that it
// will refer back to the function on the default prototype objects, so
// we do that for consistency despite nothing in JavaScript actually
// _using_ `constructor`.
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;

// Add things to `Child.prototype`
Child.prototype.one = function() {
  Parent.prototype.one.call(this);
  console.log("I'm Child#one: b = " + this.b);
};
Child.prototype.three = function() {
  console.log("I'm Child#three: b = " + this.b);
};

// A grandchild "subclass"
function GrandChild(b, c) {
  // Chain to "superclass" constructor
  // Note that GrandChild has a fixed value for Parent's `a`
  Child.call(this, "GrandChildFixedA", b);

  // Do our own init
  this.c = c;
}

// Again create a blank object to be the prototype `new GrandChild`
// assigns, again set `constructor`
GrandChild.prototype = Object.create(Child.prototype);
GrandChild.prototype.constructor = GrandChild;

// Add things to it
GrandChild.prototype.one = function() {
    Child.prototype.one.call(this);
    console.log("I'm GrandChild#one: c = " + this.c);
};
GrandChild.prototype.three = function() {
    Child.prototype.three.call(this);
    console.log("I'm GrandChild#three: c = " + this.c);
};

用法:

var p = new Parent("ParentA");
console.log("Calling p.one");
p.one();    // "I'm Parent#one: a = ParentA"
console.log("Calling p.two");
p.two();    // "I'm Parent#two: a = ParentA"
var c = new Child("ChildA", "ChildB");
console.log("Calling c.one");
c.one();    // "I'm Parent#one: a = ChildA" then "I'm Child #one: b = ChildB"
console.log("Calling c.two");
c.two();    // "I'm Parent#two: a = ChildA"
console.log("Calling c.three");
c.three();  // "I'm Child#three: b = ChildB"
var gc = new GrandChild("GrandChildB", "GrandChildC");
console.log("Calling gc.one");
gc.one();   // "I'm Parent#one: a = GrandChildFixedA" then "I'm Child #one: b = GrandChildB" then "I'm GrandChild#one: c = GrandChildC"
console.log("Calling gc.two");
gc.two();   // "I'm Parent#two: a = GrandChildA"
console.log("Calling gc.three");
gc.three(); // "I'm Child#three: b = GrandChildB" then "I'm GrandChild#three: c = GrandChildC"

测试instanceof,虽然如果你正在使用很多实例,你可能想要阅读鸭子类型:

Testing instanceof, although if you're using instanceof a lot, you might want to read up on duck typing:

// Some things that should be true
console.log("p instanceof Parent? " + (p instanceof Parent));
console.log("c instanceof Parent? " + (c instanceof Parent));
console.log("c instanceof Child? "  + (c instanceof Child));
console.log("gc instanceof Parent? " + (gc instanceof Parent));
console.log("gc instanceof Child? "  + (gc instanceof Child));
console.log("gc instanceof GrandChild? "  + (gc instanceof GrandChild));

// And some things that *shouldn't* be true:
console.log("p instanceof Child? (should be false) " + (p instanceof Child));
console.log("p instanceof GrandChild? (should be false) " + (p instanceof GrandChild));
console.log("c instanceof GrandChild? (should be false) " + (c instanceof GrandChild));

如果您不在启用ES5的环境中,可以将此垫片用于 Object.create (注意:一个完整的垫片,足以启用上述内容):

If you're not in an ES5-enabled environment, you can use this shim for Object.create (note: not a complete shim, just enough to enable the above):

Object.create = function(p) {
  var o;

  function ctor() {
  }

  ctor.prototype = p;

  o = new ctor();

  ctor.prototype = null;
  return o;
};

您可以看到为什么工具包脚本会让生活变得更轻松。你有几个可供选择。以下是使用 Lineage ,我的工具包:

You can see why a toolkit script makes life a bit easier. You have several to choose from. Here's what the above looks like using Lineage, my toolkit:

// A parent (base) "class"
var Parent = Lineage.define(function(p) {
  p.initialize = function(a) {
    this.a = a;
  };
  p.one = function() {
    console.log("I'm Parent#one: a = " + this.a);
  };
  p.two = function() {
    console.log("I'm Parent#two: a = " + this.a);
  };
});

// A child "subclass"
var Child = Lineage.define(Parent, function(p, pp) {
  p.initialize = function(a, b) {
    // Chain to "superclass" constructor
    pp.initialize.call(this, a);

    // Do our own init
    this.b = b;
  };
  p.one = function() {
    pp.one.call(this);
    console.log("I'm Child#one: b = " + this.b);
  };
  p.three = function() {
    console.log("I'm Child#three: b = " + this.b);
  };
});

// A grandchild "subclass"
var GrandChild = Lineage.define(Child, function(p, pp) {
  p.initialize = function(b, c) {
    // Chain to "superclass" constructor
    // Note that GrandChild has a fixed value for Parent's `a`
    pp.initialize.call(this, "GrandChildFixedA", b);

    // Do our own init
    this.c = c;
  };
  p.one = function() {
      pp.one.call(this);
      console.log("I'm GrandChild#one: c = " + this.c);
  };
  p.three = function() {
      pp.three.call(this);
      console.log("I'm GrandChild#three: c = " + this.c);
  };
});

用法相同。

从ES2015(又名ES6)开始,JavaScript获得了超级关键字,大大简化了上述内容,并且可以在今天使用进行转换。

As of ES2015 (aka "ES6"), JavaScript got the class and super keywords, which dramatically simplify the above, and can be used today with transpiling.

class Parent {
    constructor(a) {
        this.a = a;
    }

    one() {
        console.log("I'm Parent#one: a = " + this.a);
    }

    two() {
        console.log("I'm Parent#two: a = " + this.a);
    }
}

class Child extends Parent {
    constructor(a) {
        super(a);
    }

    one() {
        super.one();
        console.log("I'm Child#one: a = " + this.a);
    }

    three() {
        console.log("I'm Child#three: a = " + this.a);
    }
}

class GrandChild extends Child {
    constructor(a) {
        super(a);
    }

    one() {
        super.one();
        console.log("I'm GrandChild#one: a = " + this.a);
    }

    three() {
        super.three();
        console.log("I'm GrandChild#three: a = " + this.a);
    }
}

// Usage
var p = new Parent("ParentA");
console.log("Calling p.one");
p.one();    // "I'm Parent#one: a = ParentA"
console.log("Calling p.two");
p.two();    // "I'm Parent#two: a = ParentA"
var c = new Child("ChildA", "ChildB");
console.log("Calling c.one");
c.one();    // "I'm Parent#one: a = ChildA" then "I'm Child #one: b = ChildB"
console.log("Calling c.two");
c.two();    // "I'm Parent#two: a = ChildA"
console.log("Calling c.three");
c.three();  // "I'm Child#three: b = ChildB"
var gc = new GrandChild("GrandChildB", "GrandChildC");
console.log("Calling gc.one");
gc.one();   // "I'm Parent#one: a = GrandChildFixedA" then "I'm Child #one: b = GrandChildB" then "I'm GrandChild#one: c = GrandChildC"
console.log("Calling gc.two");
gc.two();   // "I'm Parent#two: a = GrandChildA"
console.log("Calling gc.three");
gc.three(); // "I'm Child#three: b = GrandChildB" then "I'm GrandChild#three: c = GrandChildC"

这篇关于具有原型和基类的JS OO模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆