1.拷贝属性方式:
如果属性的值是引用类型的,如数组、对象、方法等,那么子对象和父对象共享一块数据,修改了某个对象对另一个对象是有影响的。
var obj1 = {
name:"静静的顿河",
des:"我在静静的看着这条河",
friends:["哗啦哗啦","哈出哈赤","哔哩哔哩","哈拉哈拉"]
}
var obj2 = {};
//obj2要能够拥有obj1的属性
for (var k in obj1)
{
obj2[k] = obj1[k];
}
console.log(obj2.friends);
console.log(obj1.friends);
//更新obj1的引用类型的属性值(如这里的friends数组),obj2也会受影响。
obj1.friends.push("乌拉乌拉");
console.log(obj2.friends);
//实现拷贝的另一种方式,使用Object.assign(),其中第一个参数是目标对象,第二个,第三个参数是要拷贝属性的对象,同样的这种拷贝方式在拷贝引用类型属性时只能拷贝地址
var o = {};
var obj1 = {name:"name"};
var obj2 = {age:20};
var obj3 = {car:{type:"飞船"}};
Object.assign(o,obj2,obj1,obj3);
console.log(o);
obj3.car.type = '汽车';
console.log(o);
2.原型式继承
存在问题:1.构造器属性指向问题,指向父构造函数,需要手动修正 2.只能够继承原型属性和方法,无法继承实例属性和方法。
原型式继承A
<script>
function A(){}
A.prototype.name = "默认的名称";
var a1 = new A();
var a2 = new A();
//利用:构造函数的原型对象上面的属性和方法可以被构造函数创建出来的对象所使用
console.log(a1.name);
console.log(a2.name);
</script>
原型式继承B
<script>
function A(){};
A.prototype = {
name:"默认的名称",
// 手动修正原型对象的构造器
constructor:A
}
var a1 = new A();
var a2 = new A();
console.log(a1.name);
console.log(a2.name);
</script>
原型式继承C
<script>
function A(){
// 设置实例属性
this.name = "默认名";
this.age = 30;
};
//设置A的原型对象
A.prototype.des = "描述信息-A";
function B(){};
//设置B的原型等于A的原型,此时B的构造函数为A
B.prototype = A.prototype;
//手动修正B的原型对象的构造器
B.prototype.constructor = B;
var b1 = new B();
var b2 = new B();
//b1和b2拥有des属性
console.log(b1.des,8);
console.log(b2.des);
//验证构造器属性
console.log(b1.constructor);
console.log(b2.constructor);
var a1 = new A();
console.log(a1.constructor);
//无法获得父对象的实例属性
console.log(b1.name); //undefined
console.log(b2.name);//undefined
</script>
3.原型链继承
步骤:001 提供一个父构造函数002 提供子构造函数
003 设置子构造函数的原型对象为父构造函数的一个实例对象
003 在这个实例对象上面设置属性和方法
<script>
function A(){
this.age = 55;
this.showAge = function(){
console.log(this.age);
}
};
A.prototype.logDes = function(){
console.log("des");
}
//子构造函数
function B(){
};
//设置原型链继承:子构造函数的原型对象为父构造函数的一个实例
B.prototype = new A();
//注意点01 在设置完原型链之后需要修正构造器属性的指向
B.prototype.constructor=B;
//02 要在设置完原型继承之后再来为原型对象添加自己的属性和方法
//03 在设置完原型继承之后只能通过对象的动态特性来设置原型对象的属性和方法,而不要使用字面量的方式
B.prototype.des = "des";
B.prototype.show = function(){
console.log("show");
};
var b1 = new B();
console.log(b1.age);
b1.showAge();
b1.logDes();
console.log(b1);
</script>
原型链继承的特点:
01 无法对父构造函数传递参数
02 继承过来的实例属性会成为当前对象的原型属性,会被创建出来的多个对象所共享
4.借用构造函数实现继承:可以获得父构造函数中的实例属性,解决了传参的问题
<script>
function Person(name,age){
this.name = name;
this.age = age;
};
function Boy(bookName,name,age){
this.bookName = bookName;
//用call借用Person构造函数
Person.call(this,name,age);
}
//创建对象
var boy = new Boy("水煮三国","悟空",600);
var boy02 = new Boy("大话西游","云风",40);
console.log(boy);
console.log(boy02);
</script>
5.组合继承:原型 + 借用构造函数
01 借用构造函数实现继承:可以获得父构造函数中的实例属性 Person.call(this,name,age)
02 获得原型属性和方法 ( Boy.prototype = Person.prototype)
<script>
function Person(name,age){
this.name = name;
this.age = age;
};
Person.prototype.des = "描述信息";
Person.prototype.logDes = function(){
console.log(this.des);
};
function Boy(bookName,name,age){
this.bookName = bookName;
//借用构造函数
Person.call(this,name,age);
}
//设置原型继承
Boy.prototype = Person.prototype;
//创建对象
var boy = new Boy("水煮三国","悟空",600);
var boy02 = new Boy("大话西游","云风",40);
console.log(boy);
console.log(boy02);
boy.logDes();
var p1 = new Person();
p1.logDes();
Boy.prototype.des = "描述信息-bOY";
boy.logDes();
p1.logDes();
</script>