前言:
上篇文章说了下,原型链继承 临时构造器继承!
下面我们来说说继承其它的方法例如:属性拷贝,对象之间继承……等。
一、属性拷贝
属性拷贝也是继承的一种方式。属性拷贝是子对象会继承父对象原型链上所有的自身属性。但是,属性拷贝有一个问题,该方法只针对于对于基本数据类型有效,JS中对象的传递大多数是引用传递,仅仅是传递对象的地址,子对象修改, 父对象中也相应的会改变。
如下图:
属性拷贝代码:
function extend2(Child,Parent){
var c = Child.prototype;
var p = Parent.prototype;
// 循环遍历 Parent中的属性,复制给Child
for(var i in p){
c[i] = p[i];
}
// uber 实现子级属性能找到父级的属性
Child.uber = Parent.prototype;
}
例:
function Person(){}
Person.prototype.age = 0;
Person.prototype.description = "人类";
Person.prototype.hoby = ["权利","金钱"];
Person.prototype.say = function(){
return "我的年龄" + this.age;
};
function Student(){}
// 实现继承关系
extend2(Student,Person);
Student.prototype.description = "学生";
// 实例化一个学生对象
var stu = new Student();
stu.hoby.pop();
console.log(stu.description);
console.log(stu.hoby);
var stu1 = new Person();
console.log(stu1.description);
console.log(stu1.hoby);
就代码而言,需要更改constructor属性吗? 答案:当然不用 。
通过extend2(Student,Person);代码,所以Student中没有的属性都可以从Person中拷贝过来,因此这就是属性拷贝。但是有一个问题就是如果你修改Student中的方法、对象、数组。那就会把Person中的也改掉,所以这种方法也属于浅拷贝。这个问题一会会在深拷贝中解决。
二.对象之间的继承
到目前来说,我们都是通过构造函数实现的继承关系,其实,我们完全可以不使用构造函数就可以实现继承关系直接使用对象完成继承关系的建立。
对象代码:
function extend3(parent,child){
// 如果实参第二个参数传递了,那么child就是实参的值
// 如果实参第二个参数没有传递,那么child就是个空对象
child = child || {};
for(var i in paren ){
child[i] = parent[i];
}
child.uber = parent;
return child;
}
例:
var per = {
description:"人类",
age:0,
hoby:["权利","金钱"],
say:function(){
return this.age;
}
};
function Student(){}
var stu = new Student();
//建立继承关系(让一个已知的对象继承自per对象)
extend3(per,stu);
stu.description = "学生";
console.log(stu.age);
stu.hoby.pop();
console.log(stu.hoby);
console.log(per.hoby);
// 子对象访问父对象中的description属性
console.log(stu.uber.description);
// 创建一个继承per对象的对象
var t = extend3(per);
console.log(t.description);
对象继承也属于浅拷贝。对象继承也会有一个与属性拷贝类似的bug,也会用深拷贝来解决!!!
深拷贝:内存拷贝,将内存完整的拷贝一份
浅拷贝:引用拷贝,只复制对象地址
说了这么多方法,深拷贝终于来了!!!!
三、深拷贝
function deepCopy(parent,child){
child = child || {};
// 遍历父对象属性
for(var i in parent){
// 判断是否是自身属性
if(parent.hasOwnProperty(i)){
if(/*是对象类型*/typeof parent[i] === "object"){
// 判断是属性是否是数组([])还是对象({})
child[i] = Array.isArray(parent[i])?[]:{};
//把parent[i]里的属性赋值给child[i]里面去
deepCopy(parent[i],child[i]);
}else{
// 基本数据类型
child[i] = parent[i];
}
}
}
return child;
}
var per = {
description:"人类",
age:0,
hoby:["权利","金钱"],
say:function(){
return this.age;
}
};
// 对象t继承自对象per
var t = deepCopy(per);
t.hoby.pop();
console.log(t.hoby);
console.log(per.hoby);
console.log(t.description);
用深拷贝就可以看出如果修改方法、数组、对象就不会对父对象产生变化。
四、原型继承与属性拷贝的混合应用
写段代码来表示,如下:
var per = {
description:"人类",
age:0,
hoby:["权利","金钱"],
say:function(){
return this.age;
},
};
var base = {
name:"zhang",
height:180,
weight:70,
};
function extend(p1,p2){
var child;
var F = function(){};
F.prototype = p1;
child = new F();
for(var i in p2){
child[i] = p2[i];
}
return child;
}
var t = extend(per,base);
console.log(t)
五、多重继承
var per1 = {
name:"zhang",
}
var per3 = {
age:"16",
}
var per5 = {
name:"kun",
height:"180",
}
var per6 = {
weight:"70",
}
function muli(){
var child = {};
for(var i = 0 ;i <arguments.length ;i++){
arguments[i];
for(var j in arguments[i]){
child[j] = arguments[i][j];
}
}
return child;
}
// 对象t继承子对象per1,per3,per5,per6
// 注意:如果父对象中存在相同的属性,参数后面对象中的属性
// 会覆盖掉前面参数对象中的属性
var t = muli(per1,per3,per5,per6);
console.log(t);
JS高级理清楚面向对象、继承、闭包还是挺重要的。
继承的方法就先写到这里!!!后面会陆续更新!!!Loading...