如果我在Firefox中运行这段JavaScript代码:
function Human() {
}
function Engineer(diploma) {
this.diploma = diploma;
}
Engineer.prototype = new Human();// Line A1
Engineer.prototype.constructor = Engineer;
Engineer.prototype.getDiploma = function() {
alert(this.diploma);
};
var engineer = new Engineer("Bridges and Roads");
engineer.getDiploma();
var human = new Human();
human.getDiploma(); // Line A2
标记为“ A2”的行将在Firefox控制台中生成错误:
TypeError: human.getDiploma is not a function
还要注意,在A1行中,我使用了“ new”来模拟Engineer从Human继承的。可以在以下JSFiddle中对其进行测试:
http://jsfiddle.net/RMWdh/1/
现在,我像这样更改A1线:
function Human() {
}
function Engineer(diploma) {
this.diploma = diploma;
}
Engineer.prototype = Human.prototype;// Line B1
Engineer.prototype.constructor = Engineer;
Engineer.prototype.getDiploma = function() {
alert(this.diploma);
};
var engineer = new Engineer("Bridges and Roads");
engineer.getDiploma();
var human = new Human();
human.getDiploma(); // Line B2
请注意,A1线已被B1线代替。其余代码相同。这次,如果我运行它,则Firefox控制台中没有错误,但是我将收到一个警报,提示“桥梁和道路”(这是对engineering.getDiploma()的调用),以及另一个警报,提示“未定义”(其中是B2行的结果)。也可以在JSFiddle上检查,这里:
http://jsfiddle.net/RMWdh/2/
我的问题是:为什么会有这种差异?这样做之间有什么区别:
Engineer.prototype = new Human();
和这个:
Engineer.prototype = Human.prototype;
最佳答案
后者只是复制了引用,使“工程师是人类”和“人类是工程师”均为真。通常这不是所需的效果。
Engineer.prototype = Human.prototype;
var human = new Human();
/*
engineer ->
(Engineer.prototype & Human.prototype) ->
Object.prototype
*/
var human = new Human();
console.log('getDiploma' in human); // true
console.log(human instanceof Engineer); // true
另一方面,前者仅确定“工程师是人类”。这使
Engineer
可以将自己的身份和逻辑与其他Human
分开。在这种情况下,包括.getDiploma()
。Engineer.prototype = new Human();
var engineer = new Engineer("Bridges and Roads");
/*
engineer ->
Engineer.prototype ->
Human.prototype ->
Object.prototype
*/
var human = new Human();
console.log('getDiploma' in human); // false
console.log(human instanceof Engineer); // false
您还可以使用
Object.create()
建立prototype
chain而不需要调用构造函数:Engineer.prototype = Object.create(Human.prototype);