2009-05-31 99 views
8

我知道有很多类似的问题都是对这个很好的答案。我试图看看经典的继承方法,或者那些闭包方法等。不知何故,我认为它们对我来说或多或少是“黑客”方法,因为它实际上并不是JavaScript所设计的。 (欢迎有人纠正我,如果我错了)。 OK,只要它的作品,我满足与像经典的遗传模式:JavaScript的继承

PARENTClass = function (basevar) { do something here; }; 
PARENTClass.prototype = { a: b, c: d}; // prototype is auto gen 

// Inheritance goes here 
CHILDClass = function (childvar) { do something; }; 
CHILDClass.prototype = new PARENTClass(*1); // Actual inheritance to the prototype statement 
// Instance 
CHILDInstance = new CHILDClass(whatever); 

以上是莫名其妙,我的理解JS的继承。但是,我不知道如何实现的一个场景是,如果我想做一些初始化DURING对象创建(即在构造函数中),并且可以立即使用新对象......我对问题的示例可能不会太清楚,所以让我用下面的C#的伪解释什么是我想要做的:(像初始化UI元素)

class PARENT { 
    public PARENT (basevar) { ... } 
} 
class CHILD : PARENT { 
    public CHILD (basevar) : PARENT (basevar) // constructor of child, and call parent constructor during construct. 
    { ... } 
} 

出于某种原因,他们将在构造函数中似乎做的最好办法。任何人都有想法,我该怎么做。 PS:在* 1中,我不知道我应该放在那里。 PS2:上面的情况我DID找到了jquery.inherit库可以做的,我只是想知道是不是用库可以实现它。 PS3:或者我的理解错误。由于JavaScript不是为了模仿OOP(这就是为什么我称之为破解),什么是“正确”的逻辑来实现这一点。

+0

检查了这一点:http://stackoverflow.com/questions/7486825/javascript-inheritance/12816953#12816953 – 2012-10-10 10:35:54

+0

使用的Object.create()继承从基类的原型。通过这种方式,基类的变化会波及到子类,而不是相反。在我的博客上的更多详细信息:http://ncombo.wordpress.com/2013/07/11/javascript-inheritance-done-right/ – Jon 2013-07-11 13:47:13

回答

17

它不是hack本身; JavaScript是一种原型的语言,如通过Wikipedia为其中定义:

..classes不存在,和行为重用(被称为基于类的语言继承)通过克隆服务于现有的对象的过程中执行作为原型。

正如它所说的,类不用于JavaScript;您创建的每个对象都来自JavaScript Object; JavaScript中的所有对象都有prototype对象,并且您创建的对象的所有实例都从其对象的原型对象中继承了方法和属性。请参阅MDC prototype对象参考以获取更多信息。

由于这一点,当你调用行:

CHILDClass.prototype = new PARENTClass(); 

这使得CHILDClass对象从PARENTClass对象,它创建类似于继承的想法添加效果的方法和属性,将其原型对象以基于类的语言呈现。由于prototype对象会影响为该对象创建的每个实例,因此这允许父对象的方法和属性出现在子对象的每个实例中。

如果你想打电话给你的父类的构造函数在子类的构造函数,您使用JavaScript call功能;这允许您在子类的构造函数的上下文中调用父类的构造函数,因此将您的子类中的新原型属性设置为它们在父类中设置的属性。

您也不需要在指定*1的位置放置任何内容,因为该行仅用于将方法和属性添加到子类的原型对象;但是,请记住它调用父类的构造函数,因此如果在父类构造函数的操作中有任何基本参数,则应检查它们是否存在以避免发生JavaScript错误。

10

您可以手动在调用子类构造函数这样的父类的构造:

CHILDClass = function (basevar) { 
    PARENTClass.call(this, basevar); 
    // do something; 
}; 

这里的技巧是使用call方法,它可以让你在不同对象的情况下调用一个方法。有关更多详细信息,请参见the documentation of call

+0

我已搜索遍布此功能。我从来没有见过这么简单。我的问题是,这是一种“可接受的”方式吗?如在,这会被视为黑客?此外,这是目前,如`__proto__`不弃用? – 2014-08-27 17:09:24

1

JavaScript有没有内置用于继承层次支持类型扩展名应该是通过聚合进行,即直接加入期望的功能对象本身或它的原型,如果该属性将被实例之间共享。

然而,JS是强大到足以使实施其他形式的对象构造的可能,包括经典的继承。

给定一个clone function - 这足以补充“真”原型继承,而不是JavaScript的私生子方法 - 你exampe可以这样实现:

function ParentClass(baseVar) { 
    // do stuff 
} 

// don't overwrite the prototype object if you want to keep `constructor` 
// see http://joost.zeekat.nl/constructors-considered-mildly-confusing.html 
ParentClass.prototype.a = 'b'; 
ParentClass.prototype.c = 'd'; 

function ChildClass(childVar) { 
    // call the super constructor 
    ParentClass.call(this, childVar); 
} 

// don't inherit from a ParentClass instance, but the actual prototype 
ChildClass.prototype = clone(ParentClass.prototype); 
ChildClass.prototype.e = 'f'; 

它也可以添加一些语法糖类基于继承 - 我自己的实现can be found here

从上面的例子将随后读

var ParentClass = Class.extend({ 
    constructor: function(baseVar) { 
     // do stuff 
    }, 
    a: 'b', 
    c: 'd' 
}); 

var ChildClass = ParentClass.extend({ 
    e: 'f' 
}); 
1

我有一个轻量级的JavaScript OOP的包装,提供“类像”继承,您可以覆盖基础的方法或调用基构造函数或成员。

您定义的类是这样的:

//Define the 'Cat' class 
function Cat(catType, firstName, lastName) 
{ 
    //Call the 'Animal' constructor. 
    Cat.$baseNew.call(this, firstName, lastName); 

    this.catType = catType; 
} 
//Extend Animal, and Register the 'Cat' type. 
Cat.extend(Animal, { type: 'Cat' }, { 
    hello: function(text) 
    { 
     return "meaoow: " + text; 
    }, 
    getFullName: function() 
    { 
     //Call the base 'Animal' getFullName method. 
     return this.catType + ": " + Cat.$base.getFullName.call(this); 
    } 
}) 

//It has a built-in type system that lets you do stuff like: 

var cat = new Cat("ginger", "kitty", "kat"); 
Cat.getType()      // "Cat" 
cat.getBaseTypesAndSelf()   // ["Cat","Animal","Class"] 
cat.getType()      // "Cat" 
cat.isTypeOf(Animal.getType()) // "True" 

var dynamicCat = Class.createNew("Cat", ["tab","fat","cat"]) 
dynamicCat.getBaseTypesAndSelf() // ["Cat","Animal","Class"] 
dynamicCat.getFullName()   // tab: fat cat 

源代码,请访问:Class.js

我也有更多的细节在我的博客文章OOP in javascript

1

只是想我会提一些与传统模式的问题,你会为:

  1. 超类的引用变量将作为所有实例的基本静态变量提供。例如,如果super中有var arr = [1,2,3],并且执行instance_1.arr.push(4)instance_2.arr.push(5),所有这些实例都将“看到”所做的更改。
  2. 所以你解决1.艾曼的解决方案,Zakas称之为“偷构造”,但现在你调用构造函数两次:一次为原型,一次用于构造偷窃。解决方案 - 为您的原型使用像inheritPrototype一个帮手(我发现整个执行本在这篇文章:inheritPrototype method FWIW,这基本上是从Zakas的书的第181页和一些Crockford的研究组合来了。

  3. 无隐私(但话又说回来,你需要使用像持久对象模式的东西拿到这一点,这可能不是你想要的)

  4. 对象定义左“悬空”:解决方案 - 把一个if语句检查你的任何原型的函数,然后用原型文字定义原型。

我在github上运行所有这些示例!

对我来说,真正理解这两者同样重要:Zakas和Crockford关于对象创建和继承的书籍。我还需要尝试一些不同的JavaScript TDD框架。所以我决定在TDD框架和JavaScript对象创建&继承上创建一篇文章。它有运行代码和jspec测试!这里的链接:* My GitHub Open Source Essay/Book