js只支持实现继承,由于函数没有签名无法实现接口继承;
new的作用是什么:var obj=new Object();
- 创建obj={};
- 将__protoo__指向构造函数的原型,即obj.__proto__=Object.prototype;
- 将this指向当前对象,即Object.call(obj);
1.原型链继承
//父类型
function Parent(){
this.parentVal='parentval';
}
//父类型原型添加属性
Parent.prototype.getParentVal=function(){
return this.parentVal;
}
//子类型
function Child(){
this.childVal='childval';
}
//核心:对子类型原型进行重写,令其为一个父类型实例对象,从而延长了原型链
Child.prototype=new Parent();
//子类型原型添加属性
//!!!!此处注意,不可用对象字面量方式创建原型,因为会导致新建原型对象从而重写原型链,上一行操作失效
Child.prototype.getChildVal=function(){
return this.childVal;
}
//对子类型实例化,验证原型链继承
var instance=new Child();
instance.getChildVal(); //'childval' 获取子类型原型上的属性
instance.getParentVal(); //'parentval' 获取父类型原型上的属性
instance.constructor===Parent; //true 子类型的实例,其构造函数属性,跨越了两层指向父类型
//instance通过__proto__链接到了Child.prototype
//但由于重写了子类型对象,故再向上一层通过Person.prototype.constructor指向Parent类型
//实际再向上还有一层,即Object对象,Object.prototype上包含了如toString()、valueOf()等属性
//确定实例与原型的关系
//第一种方式:instanceof
instance instanceof Object; //true
instance instanceof Parent; //true
instance instanceof Child; //true
//第二种:isPrototypeOf()
Object.prototype.isPrototypeOf(instance); //true
Parent.prototype.isPrototypeOf(instance); //true
Child.prototype.isPrototypeOf(instance); //true
问题:实例上通过原型继承而来的 引用类型值会被所有实例共享,修改一个影响其他实例
function Parent(){
this.colors=['red','green'];
this.name='parent';
}
function Child(){};
Child.prototype=new Parent();
var instance1=new Child();
instance1.colors.push('black'); //向Child.prototype的colors数组内添加元素
instance1.name='instance1'; //新建一个与原型上name属性同名的自身属性,读取时屏蔽原型属性
var instance2=new Child();
instance2.colors; //["red", "green", "black"] 数组类型,被影响
instance2.name; //'parent' 字符串,未被影响
instance1.hasOwnProperty('name'); //true
instance2.hasOwnProperty('name'); //false
//!!!!!以上情况说明,原型中的引用类型值会被所有实例共享,而基本类型不会共享
//因为instance1.name='instance1'相当于新建一个instance1自带的name同名属性,从而屏蔽了原型上的name,故其实没修改原型
//但引用类型是一个指针,对其的修改其实就是修改了原本的值,所以原型上的引用类型其实是被共享了的
//instance1对其原型上属性的修改不会影响父类型,因为其修改的是父类型的一个实例
var parentInstance=new Parent();
parentInstance.colors; //['red','green']
parentInstance.name; //'parent'
2.借用构造函数:call
function Parent(){
this.name='parent';
this.colors=['red','blue'];
}
Parent.prototype.getParentValue=function(){
return this.name;
}
function Child(){
Parent.call(this); //核心:通过子类型中调用call,实现每次new实例时都有独立的副本,实例间不互相影响
}
var instance1=new Child();
instance1.colors.push('yellow'); //["red", "blue", "yellow"]
var instance2=new Child();
instance2.colors; //["red", "blue"]
//由于父子类型不涉及原型上的连接,故原型上的方法无法得到复用,此种方式不可取
instance1.getParentValue(); //TypeError: instance.getParentValue is not a function
3.组合继承:综合原型链与构造函数
问题:两次调用Parent构造函数,一次创建子类型原型,一次实例化子类型
虽然两次都有各自的意义,一次连接原型,一次创建实例副本;
连接原型时,同时复制了属性到子类型原型中,但第二次调用时会为子类型实例创建副本,故而遮蔽原型上的同名属性;
等于第一次的调用其实做了一部分无用功,产生了资源的不必要浪费;
function Parent(){
this.name='parent';
this.colors=['red','blue'];
}
Parent.prototype.getParentValue=function(){
return 'parent';
}
function Child(){
Parent.call(this); //借用构造函数 (第二次)
}
Child.prototype=new Parent(); //重写原型对象 (第一次)
Child.prototype.constructor=Child; //纠正constructor指向,使instanceof和isPrototyeOf可以进行类型判定
Child.prototype.getChildValue=function(){
return 'child';
}
var ins1=new Child();
var ins2=new Child();
ins1.colors.push('hello'); //["red", "blue", "hello"]
ins2.colors; //["red", "blue"]
ins1.getParentValue(); //"parent"
Child.prototype.isPrototypeOf(ins1); //true
ins1 instanceof Child; //true
4.原型式继承:Object.create(),同样有引用类型共享的问题;和大费周章创建构造函数不一样,此方法可以实现最简单的类继承
5.寄生式继承:类似上一种的原型式继承,但无函数复用
6.寄生组合式继承:相比于组合式继承,新建了两个函数,少调用一次父构造函数
(暂时还不能理解其中的意义,后续再补充吧)
//此函数返回一个继承自obj的实例对象,起到一个中转的作用
function createInstance(obj){
function F(){};
F.prototype=obj;
return new F();
}
//获取超类型的一个副本,避免了通过new调用超类型构造函数
function inheritPrototype(subType,superType){
var prototype=createInstance(superType.prototype);
prototype.constructor=subType;
subType.prototype=prototype;
}
function Parent(){
this.name='parent';
this.colors=['red','blue'];
}
Parent.prototype.getParentValue=function(){
return 'parent';
}
function Child(){
Parent.call(this); //借用构造函数
}
inheritPrototype(Child, Parent); //相比组合继承,修改的部分
Child.prototype.getChildValue=function(){
return 'child';
}
//实例化验证
var ins1=new Child();
var ins2=new Child();
ins1.colors.push('hello'); //["red", "blue", "hello"]
ins2.colors; //["red", "blue"]
ins1.getParentValue(); //"parent"
Child.prototype.isPrototypeOf(ins1); //true
ins1 instanceof Child; //true