标签:
经常被问到js的继承以及原型链(prototype chain)的知识,每每看过之后都很快遗忘,现整理一下自己了解的情况,以加深了解。
一、js对象
js里面都是对象,没有“类”的概念,我们使用new操作来从原型对象生成一个实例对象,例如:
function Parent(name){
this.name = name;
this.get = function(){
return this.name;
}
}
对这个构造函数(注意Parent不是一个类,只是一个构造函数,this指向新创建的实例)使用new,就生成一个人对象的实例,
var p1 = new Parent(‘p1‘);
console.log(p1.name); //p1
二、new的缺点:
无法共享属性和方法,当new两个对象时,生成两个实例对象,它们的属性是独立的,不会互相影响:
var p2 = new Parent(‘p2‘);
console.log(p2.name);//p2
console.log(p1.name);//p1
每一个实例对象,都有自己的属性和方法的副本,不仅无法数据共享,而且浪费资源。
三、prototype属性
这个属性包含一个对象,所有实例对象需要共享的属性和方法,都放在此对象里面;那些不需要共享的属性和方法,就放在构造函数里面。
实例对象一旦创建,将自动引用prototype对象的属性和方法。实例对象的属性和方法分为两种,一种是独立的(构造函数中的),一种是共享引用的(原型链中的);
四、继承方法
了解了js对象的构造之后,就来总结下各种不同的继承方法。
1.构造函数继承法(利用apply&call实现)
使用上面的Parent作为父对象,现实现一个子对象
var Child = function(){
Parent.apply(this,arguments);
this.sex = "male";
}
Parent.prototype.log = function(){
console.log(this.name)
}
var c1 = new Child(‘c1‘);
c1.name; //‘c1‘
c1.log;//undefined
alert(oB instanceof a);// false
此方法只继承了构造函数中的属性和方法,能实现多重继承,但是原型链中的属性和方法无法继承,而且不能用instanceof来验证实例。
2.原型链继承
直接将子对象的prototype指向父对象的一个实例,这样就将父对象的构造函数和原型链中的属性和方法都继承到子对象的原型链上,例如:
var ChildPro1 = function(){this.sex = "female"};
ChildPro1.prototype = new Parent();
ChildPro1.prototype.constructor = ChildPro1;//指向自己的构造函数
var cp1 = new ChildPro1();
ChildPro1; //function (){this.sex = "female"}
ChildPro1.prototype;//Parent {name: undefined,get:function, log: function}
cp1.name;//undefined,没有在构造函数中赋值
cp1.get;//function (){return this.name}
cp1.log;//function (){console.log(this.name)}
这种继承方式可以继承父对象的两种属性和方法,但是每次继承都要new一个父对象的实例,为了节省内存,采用另一种方式,直接继承prototype
var ChildPro2 = function(){};
ChildPro2.prototype = Parent.prototype;
ChildPro2.prototype.construnctor = ChildPro2;
var cp2 = new ChildPro2();
cp2.get;//undefined
cp2.log;//function (){console.log(this.name)}
与前一种方法相比,这样做的优点是效率比较高(不用执行和建立Parent的实例了),比较省内存。缺点是 ChildPro2.prototype和Parent.prototype现在指向了同一个对象,那么任何对ChildPro2.prototype的修改,都会反映到Parent.prototype。
利用一个空对象作为中介来实现:
function extend(Child,Parent){ |
F是空对象,所以几乎不占内存。这时,修改Child的prototype对象,就不会影响到Parent的prototype对象。
若此时想要继承父对象构造函数中的方法和属性,可以在子对象的构造函数中使用apply来继承,即混合继承,
var ChildAll = function(){Parent.apply(this,arguments)};
extend(ChildAll,Parent) ;
var ca1 = new ChildAll(‘ca1‘);
ca1.name;//ca1
ca1.get();//ca1
ca1.log();//ca1
3.拷贝继承法
上面是采用prototype方式来实现继承。其实既然子对象会拥有父对象的属性和方法,我们直接采用”拷贝”方法也可以达到效果。简单说,如果把父对象的所有属性和方法,拷贝进子对象,不也能够实现继承吗?
function extendCopy(Child, Parent) {
var p = Parent.prototype;
var c = Child.prototype;
for (var i in p) {
c[i] = p[i];
}}
这个函数的作用,就是将父对象的prototype对象中的属性,一一拷贝给Child对象的prototype对象。
浅拷贝
function LightCopy(p) {
var c = {};
for (var i in p) {
c[i] = p[i];
} //c.uber = p;
return c;
}
深拷贝
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;}
标签:
原文地址:http://www.cnblogs.com/soullover/p/4236652.html