fucntion Person(name,sex){ //父类
this.name=name;
this.sex=sex;
}
Person.prototype.showName=function(){
alert(this.name);
}
function Star(){} //子类
现在有一个新的对象 Star,去继承Person,并给Star添加自己的新属性job,和新方法 sing。
对象的属性继承和方法继承。
属性继承:通过父类的构造函数继承(使用call函数);
//属性继承:调用父类的call
fucntion Star(name,sex,job){
// ❌ Person(name,sex) //如果直接用Person(),因为函数Person()直接被调用,所以Person函数中的this指向的是window。
Person.call(this,name,sex) //继承Person的属性,使用call。使用call函数,将this指向为新创建的对象p2。
this.job=job;
}
但是方法继承的时候我们不能直接使用原型赋值
//❌ Star.prototype=Person.prototype; //为对象赋给对象,为对象的引用,所以这两个对象指向的是同一存储空间,任意一个对象的修改都会引起另一个的变化。因此,我们要将对象的赋值改变为基本类型的赋值。
继承:拷贝继承、类式继承、原型继承
1、拷贝继承(for in) ( jquery的extend函数也是拷贝继承。$.extend(),当把第一个参数设置为true时,为深拷贝)
封装extend函数:(将obj2拷贝给obj1)
function extend(obj1,obj2){
for(var attr in obj2){
obj1[attr]=obj2[attr];
}
}
使用方法:extend(Child.prototype,Parent.prototype);
这种拷贝写法适合所有属性都是基本类型的对象。当某个属性为一个数组或是一个对象时,这样的拷贝无法实现数组、对象的真正拷贝。也就是这种写法实际上是浅拷贝。
若想实现深拷贝,只要递归调用浅拷贝方法即可:
function extend(obj1,obj2){
for(var attr in obj2){
if (typeof obj2[i] === 'object') { //当某个属性的值为一个对象时,需要递归调用extend
obj1[i] = (obj2[i].constructor === Array) ? [] : {}; //创建空的数组或对象
extend(obj1[i], obj2[i]);
} else {
obj1[attr]=obj2[attr];
}
}
}
在这个例子中:extend(Star.prototype,Person.prototype);
Star.prototype.sing=function(){
alert('sing a song');
}
2、类式继承(构造函数)
JS中没有类,但是我们可以把JS中的构造函数看作类。
Star.prototype=new Person(); //用父类的实例,赋值给子类的原型。它相当于完全删除了prototype 对象原先的值,然后赋予一个新值。
//这时,Star.Prototype.constructor=Person,这显然会导致继承链的紊乱,因此我们必须手动纠正,将Star.prototype对象的constructor值改为Star。
Star.Prototype.constructor=Star;
另外一个问题:当我们创建两个实例:
s1=new Star();
s2=new Star(); //测试会发现s1和s2之间的属性不是独立的,因为它们的继承都来自Person。当s1的属性变化时,s2也会受到影响。为了避免这个问题,我们需要属性和方法分开继承。
我们需要一个空对象,作为中间桥梁:
var F=funtion(){};
F.prototype=Person.prototype;
所以最终的类式继承,需要4句话:
var F=funtion(){}; F.prototype=Person.prototype; //只会复制方法,属性并没有复制。
Star.prototype=new F(); //所以这时候Star只是接收了父类的方法,而没有接收父类的属性。要想继承父类的属性,仍然使用Person.call(this)的方法。this的指向不同,因此s1和s2的属性不会相互干扰。
Star.prototype.constructor=Star;
3、原型继承(借助prototype)
var A={
name:'a';
}
var B=cloneObj(A);
function cloneObj(obj){
var F=function(){};
F.prototype=obj;
return new F();
}
B继承了A。且B和A的属性相互独立。
总结:
(1)拷贝继承:通用
(2)类式继承:适合通过new构造函数
(3)原型继承:适合无new的对象