今天介绍一下对象之间继承的五种方式
下面有两个构造函数:
function Animal(){ this.species = "动物"; }
function Cat(name,color){ this.name = name; this.color = color; }
现在我们怎么使得Cat继承Animal?
以下我们用五种方法来实现继承
一、 构造函数绑定(call、apply)
这种方法直接简单,使用call或apply直接将父对象的构造函数绑定在子对象上
function Cat(name,color){ Animal.apply(this, arguments); this.name = name; this.color = color; } var cat1 = new Cat("大毛","黄色"); alert(cat1.species); // 动物
二、 prototype模式
javaScript规定,每一个构造函数都会有一个prototype属性,指向另一个对象,而这个对象所有的方法和属性,都会被
构造函数的实例继承。
如果Cat的prototype对象,指向Animal的一个实例,那么所有Cat的实例,也就理所当然的能够继承Animal了。
Cat.prototype = new Animal(); Cat.prototype.constructor = Cat; var cat1 = new Cat("大毛","黄色"); alert(cat1.species); // 动物
我们来分析一下这段代码。
Cat.prototype = new Animal();这行代码让Cat的prototype对象指向了一个Animal的实例。
它相当于完全删除了prototype对象原来的值,然后赋予一个新的值。
但是,这样会有一个问题出现,就是Cat.prototype,constructor会指向Animal,所以,
Cat.prototype.constructor = Cat;这行代码让Cat.prototype的constructor指向Cat,不至于导致继承链的紊乱。
三、 直接继承prototype
我们可以把Animal对象中不变的属性写入Animal.prototype。这时候,我们就可以直接去Animal.prototype。
我们将Animal对象改写一下:
function Animal(){ } Animal.prototype.species = "动物";
然后,将Cat的prototype对象指向Animal的prototype对象。
Cat.prototype = Animal.prototype; Cat.prototype.constructor = Cat; var cat1 = new Cat("大毛","黄色"); alert(cat1.species); // 动物
虽然这种方法实现了继承,但是,当我们修改Cat.prototype时,会反映到Animal.prototype。
还有一个问题就是当添加了Cat.prototype.constructor = Cat;这行代码的时候,我们会发现
Animal.prototype.constructor = Cat,把Animal的constructor 也修改了,所以这种方法不是很完美。
四、 利用空对象作为中介
利用一个空的对象作为一个中介
var F = function(){}; F.prototype = Animal.prototype; Cat.peotorype = new F(); Cat.prototype.constructor = Cat;
F是个空对象,几乎不占用内存,这时候修改了Cat.prototype的属性。
我们将上面的方法,封装成一个函数,便于使用。
fnntion extend(Child,Parent){ var F = function(){}; F.prototype = Parent.prototype; Child.peotorype = new F(); Child.prototype.constructor = Child; Child.uber = Parent.prototype; }
使用方法:
extend(Cat,Animal); var cat1 = new Cat("大毛","黄色"); alert(cat1.species); // 动物
控对象继承,可以说是一种很完美的继承方法,推荐大家使用。
五、 拷贝继承
如果把父对象的所有属性和方法,拷贝进子对象,也能够实现继承。
首先,还是把Animal的所有不变属性,都放到它的prototype对象上。
function Animal(){} Animal.prototype.species = "动物";
然后,再写一个函数,实现属性拷贝的目的。
function extend2(Child, Parent) { var p = Parent.prototype; var c = Child.prototype; for (var i in p) { c[i] = p[i]; } c.uber = p; }
使用方法:
extend2(Cat, Animal); var cat1 = new Cat("大毛","黄色"); alert(cat1.species); // 动物
非构造函数的继承
在最后我又加了一种Jquery里面使用的继承方法。叫做深拷贝方法。
下面是两个对象
var Person = { nation:"中国", place:["美国","英国","法国"] }
var Superman = { name:"超人" }
深拷贝函数封装,它在里面区别了对象和数组两种情况
function deepCopy(p,c){ var c = c ||{}; for(var i in p){ if(typeof p[i] === 'object'){ c[i] = (p[i].constructor == Array) ? [] : {}; deepCopy(p[i],c[i]); }else{ c[i] = p[i]; } } return c }
使用方法:
var Superman = deepCopy(Person); console.log(Superman.nation);//中国 Superman.place.push('日本') console.log(Superman.place); console.log(Person.place);
深拷贝的好处就是当你修改子对象的属性的时候不会对父对象的属性有影响。
目前,jQuery内部实现继承就是采用的这种方法。