1

开始的代码是这样的

var Animal = function(name){
    this.name = name;
};
Animal.prototype.jump = function(){
    console.log('jumped');
};

原型链继承法(对象之间的继承)

优点:将可共享的可重用的部分(属性或者方法)迁移到原型链上,将不可重用的部分作为对象的实例属性(属性)

var Human = function(name){
    this.name = name;
};
// 这一步会使得
// Human.prototype.constructor = Animal;
// 所以需要重新手动重定向
Human.prototype = new Animal;//将父构造函数的实例对象赋值给一个子构造函数的原型
// 如果不更改
// 通过`Human`构造器构造出来的对象的构造器会变成`Animal`而不是`Human`
Human.prototype.constructor = Human;(有new就要手动修改)
var man = new Human('HaoyCn');
man.jump();

现在,对象 man 可以使用 Animal.prototype.jump 方法,查找过程是:

man 自身没有jump方法
查找 man.constructor.prototype,即Human.prototype,可Human.prototype本身也没有 jump 方法,而它又是一个由Animal 构造的对象,所以
查找 Animal.prototype,在其中找到了 jump 方法,执行之

clipboard.png

创建一个实例对象,对象的prototype指向构造函数的原型(man.constructor.prototype),构造函数中的this指向这个实例对象,运行构造函数,对实例对象的属性进行赋值,返回这个实例对象

仅从原型继承法(构造函数之间的继承)

优点:提高了运行时的效率,没有创建新对象出来。

var Human = function(name){
    this.name = name;
};
Human.prototype = Animal.prototype;//将一个父构造函数的原型直接赋值给子构造函数的原型
var man = new Human('HaoyCn');
man.jump();

man 自身没有jump方法
查找 man.constructor.prototype,即Human.prototype,Human.prototype是对Animal.prototype 的引用,在其中找到了 jump 方法,执行之减少了一步。
然而代价则是:对 Human.prototype 的修改都会影响到 Animal.prototype,因为前者是对后者的引用。

一个致命缺点就是,无法修正子类构造的对象的 constructor。

clipboard.png

man.constructor === 
    man.__proto__.constructor === 
    Human.prototype.constructor ===
    Animal.prototype.constructor ===
Animal

临时构造函数继承法(类式继承,构造函数之间的继承+对象间的继承)

var F = function(){};//创建要给空的函数(构造函数:中介构造器)
F.prototype = Animal.prototype;//父构造函数的原型赋值给空构造函数的原型

var Human = function(name){
    this.name = name;
};
Human.prototype = new F;//空(父)构造函数的实例对象赋值给子构造函数的原型
Human.prototype.constructor = Human;//手动修改重定向constructor(有new就要修改)
Human.prototype.sing = function(){
    console.log('Mayday');
};
var man = new Human('HaoyCn');
man.jump();
man.sing();

我们对 Human.prototype 的任何改变都变成了对一个由中介构造器创建的对象的属性的修改。jump查找过程是:

man 自身没有jump方法
查找 man.constructor.prototype,即Human.prototype,可Human.prototype本身也没有jump 方法,而它又是一个由 F 构造的对象,所以
查找 F.prototype,即 Animal.prototype,在其中找到了 jump 方法,执行之

clipboard.png

先看“原型链继承法”中的操作:
Human.prototype = new Animal;
// 这将造成:
// Human.prototype.name = undefined;// 没有给`Animal`传入参数之故
也就是说,Human.prototype 会多出不必要的属性来,而中介器则避免了这种不必要的属性。

构造器借用法

以上继承法共通的一个缺点在于,Human 构造器构造的对象虽然可以共用 Animal.prototype,但对于name 属性而言,Human 构造器只能自己再写一遍构造 name 属性,为什么不把初始化属性的方法也共(借)用呢?
构造器借用法应运而生。现在我们把 name 属性的创建还是交给 Animal,然后再为 Human 增加country 属性。我们在“临时构造器法”基础上进一步完善之。

var F = function(){};//创建要给空的函数(构造函数:中介构造器)
F.prototype = Animal.prototype;//父构造函数的原型赋值给空构造函数的原型
//创建子构造函数
var Human = function(){
    Animal.apply(this,arguments);//this.Animal(arguments):借用构造器Animal,是初始化属性的方法也共用(偷懒)
    this.country = arguments[1];
}

Human.prototype = new F;//空(父)构造函数的实例对象赋值给子构造函数的原型
Human.prototype.constructor = Human;//手动修改重定向constructor

var man = new Human('HaoyCn','China');
console.log(man.country);// China

clipboard.png


时间冒泡
101 声望4 粉丝

在路上。


引用和评论

0 条评论