3

我是 JavaScript 新手(本周开始学习它)。我已经完成了 CodeCademy 课程(实际上只是 Objects 1 && 2 部分,其余部分很无聊)。我以为我学习了构造函数的原型继承,但我开始观看Douglas Crockford: Advanced JavaScript

就在视频的开头,他提到了两种继承,我意识到,我以为我知道的一切,我都不知道。所以我开始使用 Chrome JavaScript 控制台并尝试使用这两种继承模型来做一些事情。

//create constructor
function MyParent(){ 
    this.name = "joe";
    this.sayHi = function(){ 
        console.log(this.name); 
    }
}

//create child object and inherit from parent
var myChild1 = new MyParent();
myChild1.name
"joe"
myChild1.sayHi()
joe

//add method to MyParent, so it can be accessed from myChild1
MyParent.prototype.sayBye = function(){ console.log("bye");}

myChild1.sayBye()
bye

//create another constructor
function MyParent2(){
    this.sayHi = function(){ 
        console.log("hi"); 
    }
}

//make it inherit from MyParent, overwriting sayHi if object is instance of MyParent2
MyParent2.prototype = new MyParent();

//overwrote sayHi
var myChild11 = new MyParent2(); 
myChild11.sayHi();
hi

//still same as MyParent as its not overwriten in MyParent2
myChild11.name
"joe"

比我尝试使用 Object.create 做同样的事情:

//create an object
 var myParent = { 
    name : "joe",
    sayHi : function(){ 
        console.log(this.name) 
    } 
};

//it works
myParent.sayHi()
joe

//create child object
var myChild = Object.create(myParent);
myChild.sayHi()
joe

//add bye method to myChild
myChild.sayBye = function(){ console.log("bye"); }
myChild.sayBye();
bye

//add bye method to myParent - does not overwrite child's bye
myParent.sayBye = function(){ console.log("bye2"); }

//however adding sayBye2 to parent, becomes available on already created child
myParent.sayBye2 = function(){ console.log("bye2"); }
myChild.sayBye2();
bye2
//but its the parent property
myChild.hasOwnProperty("sayBye2")
false

//could make million objects inherit from each other vertically or horizontally
var myChild2 = Object.create(myChild);
myChild2.name
"joe"

到目前为止,仅凭第一印象,我都喜欢这两个模型,也许我更喜欢后者。它似乎更具表现力和力量。

我已经对该vs.主题进行了一些搜索,但找不到一篇好的文章,可以解释每种方法的优缺点(除了后者仅由较新的浏览器支持,但有一个简单的解决方法)。我发现的其他帖子只是 tl: dr; 并且有些无聊。

所以我的问题是,我应该使用哪种类型的继承。是否有任何相关的特权?两者都有什么主要的缺点吗?可以混用吗?(例如,我知道您可以将对象作为参数传递给new Constructor()))

谢谢

编辑:如果浏览器不支持它,看看创建 Object.create() 替代方案的技巧,我意识到黑客是多么简单。它基本上是创建一个空的构造函数,将父对象分配为其原型,并将构建的构造函数作为新对象返回。多么整洁的黑客!

if(typeof Object.create !== "function") { Object.create = function (o) { function F() {}; F.prototype = o; return new F(); }; }

但有什么影响?有什么需要注意的问题吗?

4

2 回答 2

3

两种方式同样强大。有人说如果你不接受原型方法,你就不是真正的 JavaScript 大师,但实际上一切仍然只是原型继承,这是风格问题。

就个人而言,我更喜欢使用经典方法并将new关键字与constructor函数一起使用。

为什么?

  • 经典模型是众所周知的。
  • 我不必init在我的对象上实现一个函数,只是为了做 aconstructor已经做的事情。您可能已经注意到,原型方法让您没有 a ,因此如果您需要为新创建的对象运行一些初始化逻辑,constructor则必须实现一个初始化函数(通常称为)。init

但是,我发现原型方法不那么冗长,并且对于没有实现经典继承的语言的强大背景的程序员来说可能更容易理解。

顺便说一句,使用经典模型应该避免new的一件事是像上面所做的那样使用关键字进行继承,因为您正在运行constructor不必要的父逻辑,并且它可能会产生不良的副作用。

你应该使用Object.create如下:

function A(val) { this.val = val; }
A.prototype.alertVal = function () { alert(this.val); };

function B(val) {
    A.call(this, val); //call parent constructor
}

B.prototype = Object.create(A.prototype); //inherit from A
var b = new B('test');
b.alertVal(); //test

最后,这完全取决于品味,我尊重这两种方式。也许其他人会想用一些真正的优点/缺点来改进这个答案,但我找不到任何东西。

于 2013-04-08T05:48:11.050 回答
0

构造对象new被认为是邪恶的,因为您可能忘记使用它,然后您添加的任何属性this最终都会添加到全局对象中。出于这个原因,我采用第二种方法。

我学到的另一件事是,您不应该尝试将“经典”OOD 应用于 JavaScript。它有它自己的方式应该被理解,实际上它非常好。我认为 JavaScript 中的大多数对象编程问题都来自尝试将“类”的概念延伸到 JavaScript 上。

于 2013-04-08T04:39:07.713 回答