继承

 js只支持实现继承,由于函数没有签名无法实现接口继承;

new的作用是什么:var obj=new Object();

  1. 创建obj={};
  2. 将__protoo__指向构造函数的原型,即obj.__proto__=Object.prototype;
  3. 将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

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值