function Animal(){} Animal.prototype.type = '猫科动物'; function Cat(name, age) { this.name = name; this.age = age; }
想要使Cat继承Animal的prototype属性
方法一:构造函数的绑定,使用call或者apply将父对象的构造函数绑定在子对象上
function Cat(name, age) { Animal.apply(this,arguments); this.name = name; this.age = age; } var cat1 = new Cat('大猫',3); console.log(cat1.type)//动物
方法二: 使用prototype属性
Cat.prototype = new Animal(); Cat.prototype.constructor = Cat; var cat1 = new Cat(); console.log(cat1.type)
代码第一行,我们将Cat的prototype对象指向一个Animal实例
Cat.prototype = new Animal();
它相当于完全删除了prototype对象原先的值,然后赋予一个新值。
Cat.prototype.constructor = Cat
任何一个prototype对象都有一个constructor属性,指向它的构造函数,如果没有Cat.prototype = new Animal()这句话,Cat.prototype.constructor是指向Cat的,加入这行之后,Cat.prototype.constructor是指向Animal的
console.log(Cat.prototype.constructor === Animal)//true
更重要的是,没一个实例也有一个constructor属性,默认调用prototype对象的constructor属性
console.log(cat1.constructor === Animal)//true
因此,在执行Cat.prototype = new Animal();这行之后,cat1.constructor也指向Animal!
这样就会导致紊乱(cat1明明是用构造函数Cat生成的),因此,必须手动纠正,讲Cat.prototype.constructor = Cat,这就是第二行代码的意思。
这是很重要的一点,编程时务必要遵守,下文都遵守这一点,即如何替换了prototype对象,
o.prototype = {}
那么,下一步必然是为新的prototype对象加上constructor属性,并将这个属性指向原来的构造函数
o.prototype.constructor = o;
方法三:直接继承prototype
function Animal(){} Animal.prototype.type = '动物'; function Cat(name, age) { this.name = name; this.age = age; } Cat.prototype = Animal.prototype; Cat.prototype.constructor = Cat; var cat1 = new Cat(); console.log(cat1.type)//动物
此种方法优点是效率高,省内存。缺点是Cat.prototype.constructor = Cat这句话将Animal.prototype.constructor也一起改了,指向了Cat。
方法四:在方法三的基础上优化出来,利用空对象作为中介
function extend(child,parent){ var F = function(){}; F.prototype = parent.prototype; child.prototype = new F(); child.prototype.constructor = child; } extend(Cat,Animal); var cat1 = new Cat();
console.log(cat1.type)//动物
这是YUI库如何实现继承的方式
方法五:把父对象的所有属性拷贝进子对象,也能够实现继承
function extend2(child,parent){ var p = child.prototype; var c = parent.prototype; for(var i in c){ p[i] = c[i] } } extend2(Cat,Animal); var cat1 = new Cat(); console.log(cat1.type)//动物