js对象继承理解
一.原型链:
用法:把实例的父类给子函数的原型
缺点:
1》因为修改了obj1.arr后obj2.arr也变了,因为来自原型对象的引用属性里所有实例共享的
2》创建子类实例时,无法向父类构造函数传递参数
function Parent(){//父
this.userName = "父函数";
this.arr = [1,2,3];
}
function Child(){//子
this.age = 18;
}
Child.prototype=new Parent();
//原型链===》核心:把实例的父类给子函数的原型
var obj1 = new Child();
var obj2 = new Child();
//console.log(obj1.userName);
obj1.arr[0] = "张三";
console.log(obj1.arr);//张三,2,3
console.log(obj2.arr);//张三,2,3
二.借用构造函数
核心:借父类的构造函数来增强子类实例,就是说,相当于复制了一份父类的属性或者方法给子类了
优点:
a)解决了子类实例共享父类引用属性的问题
b)创建子类实例时,可以向父类构造函数传递参数
缺点:
a)无法实现复用(不是共享的),每一个子类实例都有一个新的run函数,如果实例的对象多了,内存消耗过大
function Parent(name,arr){
this.userName = name;
this.arr = arr;
this.run = function(){
return 1111;
}
}
function Child(name,arr){
this.age = 18;
Parent.call(this,name,arr); //借用构造函数 ====》 核心代码
}
var obj1 = new Child("张三",[4,5,6]);
var obj2 = new Child("张三",[4,5,6]);
/*console.log(obj1.userName);
console.log(obj2.userName);*/
obj1.arr[0] = "你好构造函数";
console.log( obj1.arr );//你好构造函数,5,6
console.log( obj2.arr );//4,5,6
三.继承方式:(最常用的继承方式)
a)组合继承(原型链和借用构造函数组合)
优点:
1》不存在引用属性共享的问题
2》可传递参数
3》方法可复用
缺点:(小瑕疵)
子类原型上有一份多余的父类实例的属性
function Parent(name,arr){
this.userName = name;
this.arr = arr;
}
Parent.prototype.run = function(){
return "我是run方法";
};
function Child(name,arr){
Parent.call(this,name,arr);
//借用构造函数===>核心语句 1》不能复用
}
Child.prototype=new Parent();
//原型链===》核心语句
//1》不能传递参数2》arr是引用属性,一个改变,互相影响
var obj1 = new Child("张三",[1,2,3]);
var obj2 = new Child("李四",[1,2,3]);
b)原型式继承(不要与原型链搞混了)
核心:用一个函数,生出来一个新的对象
优点:从已有对象繁衍出新的对象,不需要创建自定义类型
缺点:
1》原型的引用属性会互相影响(公用一个地址)
2》无法实现代码复用,属性是后添加的,都没用到函数封装
function fn(obj){ //用来生新对象的
function F(){}//构造函数
F.prototype=obj; //F新的对象
return new F();
}
var obj = {
name:"张三",
age:187
};
var obj1 = fn(obj);
var obj2 = fn(obj);
alert(obj1.name);//张三
ES5 之后用Object.create()实现原型式继承
c)寄生式继承
核心:创建新对象===》增强对象(添加属性或者方法)===》返回对象
(与工厂模式思想类似)
function fn(obj){
var F = function(){};
F.prototype=obj;
return new F();
}
//原型式
function getSub(obj){
//寄生核心
var clone = fn(obj);
//新对象
clone.attr1 = "class";
clone.attr2 = "id";
clone.brr = [1,2,3,];
//增强
return clone;
}
var o = {
name:"张三",
age:18,
arr:[1,2,3]
};
var obj1 = new getSub(o);
var obj2 = new getSub(o);
obj1.brr[0] = "张三";
console.log(obj1.brr);//张三,2,3
console.log(obj2.brr);//1,2,3
d)寄生组合式继承
优点:修正组合继承的缺点,只使用一次构造函数
缺点:写法繁琐
function fn(obj){
var F = function(){};
F.prototype=obj;
return new F();
}
function Sub(){
this.str = "张三";
//基本属性
this.arr = [1,2,3];
//引用属性
}
Sub.prototype.run = function(){
return "共享的run方法";
};
function SubType(){
Sub.call(this); //核心代码 ===》借用sub构造函数
}
var obj1 = fn(Sub.prototype);//核心===》传递原型
obj1.constructor = SubType; //构造函数指向
Sub.prototype = obj1; //实例对象赋值给sub原型
var obj2 = new SubType();
var obj3 = new SubType();
obj2.arr[0] = "张三";
console.log(obj2.arr);//张三,2,3
console.log(obj3.arr);//1,2,3
console.log(obj2.run == obj3.run);//true