面向对象分为封装、继承,之前介绍了如何"封装"数据和方法,以及如何从原型对象生成实例,今天来详细看一下面向对象里面的构造 函数继承;
今天要介绍的是,对象之间的"继承"的五种方法。
1.首先我们定义俩个构造函数,
//比如有一猫的构造函数; function Animal (){ this.species = "动物"; } //还有一个猫的构造函数 function Cat (name,color){ this.name = name; this.color = color; }
2.第一种方法 call apply 方法继承;
function Animal (){ this.species = "动物"; } //实现继承,使用call apply方法 function Cat (name,color){ Animal.call(this,arguments); this.name = name; this.color = color; } var cat1 = new Cat('大麦','黑色'); console.log(cat1.species); //动物 -- 这里是通过Call方法继承过来的;
Ps:通过call方法 改变this指向,从而将Animal的属性继承过来;
3.第二种方法 prototype模式
function Animal (){ this.species = "动物"; } function Cat (name,color){this.name = name; this.color = color; } //prototype模式 Cat.prototype = new Animal();//此处指向变成Animal; //将指向重新指向Cat; Cat.prototype.constructor = Cat; Cat.prototype.run = function (){ alert(this.name) } var cat1 = new Cat('大麦','黑色'); console.log(cat1.species);
Ps:值得注意的是constructor指向,一定让他重新指向自己本身;
4.第三种 直接原型继承
第三种方法是对第二种方法的改进。由于Animal对象中,不变的属性都可以直接写入Animal.prototype。所以,我们也可以让Cat()跳过 Animal(),直接继承 Animal.prototype。
function Cat (name,color){ this.name = name; this.color = color; } function Animal (){}; Animal.prototype.species = '动物'; Cat.prototype = Animal.prototype;//缺点是俩个同时指向一个对象,当修改任何一个的时候都会影响另外一个; //值得注意的是这一块指向,一定让他重新指向自己本身; Cat.prototype.constructor = Cat; var cat1 = new Cat('大毛','黑色'); console.log(cat1.species);//动物
ps:缺点是俩个同时指向一个对象,当修改任何一个的时候都会影响另外一个;
5.第四种方法 利用空对象作为媒介
由于"直接继承prototype"存在上述的缺点,所以就有第四种方法,利用一个空对象作为中介。
function Animal (){}; Animal.prototype.species = '动物'; function Cat (name,color){ this.name = name; this.color = color; } //F是空对象,所以几乎不占内存。这时,修改Cat的prototype对象,就不会影响到Animal的prototype对象。 var F = function (){}; F.prototype = Animal.prototype; Cat.prototype = new F(); Cat.prototype.constructor = Cat; var cat1 = new Cat(); console.log(cat1.species);
使用的时候我们可以将上面的进行封装;
//我们将上面的封装成一个函数; function extend (child,parent){ var F = function (){}; F.prototype = parent.prototype; child.prototype = new F(); child.prototype.constructor = child; //意思是为子对象设一个uber属性,这个属性直接指向父对象的prototype属性。(uber是一个德语词,意思是"向上"、"上一层"。)这等于在子对象上打开一条通道,可以直接调用父对象的方法。这一行放在这里,只是为了实现继承的完备性,纯属备用性质。 child.uber = parent.prototype; } extend(Cat,Animal); var cat1 = new Cat(); console.log(cat1.species);
6、最后一种方法 拷贝继承
function Animal (){}; Animal.prototype.species = '动物'; function Cat (name,color){ this.name = name; this.color = color; } 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(); console.log(cat1.species)//动物