javascript 原型链维护和继承详解

 更新时间:2014年11月26日 09:24:10   投稿:hebedich  
本文通过实例详细向我们分析了javascript原型链维护和继承的问题,十分的详尽,十分的全面,这里推荐给大家。

一.两个原型

很多人都知道javascript是原型继承,每个构造函数都有一个prototype成员,通过它就可以把javascript的继承演义的美轮美奂了.
其实啊,光靠这一个属性是无法完成javascript的继承.
我们在代码中使用的prototype完成继承在这里就不多说了.大家可以查一下资料.
另外一个看不见的prototype成员.
每一个实例都有有一条指向原型的prototype属性,这个属性是无法被访问到的,当然也就无法被修改了,因为这是维护javascript继承的基础.

复制代码 代码如下:

//构造器声明
        function Guoyansi(){ }
        function GuoyansiEx(){}
        //原型继承
         GuoyansiEx.prototype=new Guoyansi();
       //创建对象
       var g1=new GuoyansiEx();
       var g2=new GuoyansiEx();

上面的代码中的对象可以用下面的图来说明

二.原型的维护

一个构造器产生的实例,其constructor属性总是指向该构造器.我们暂且认为该话是对的.

复制代码 代码如下:

function Guoyansi(){ }
var obj1=new Guoyansi();
console.log(obj1.constructor===Guoyansi);//true

其实构造器本身是没有constructor这个属性的,那么这个属性是来自哪呢?
答案是:来自原型.
因此得出下面的结论

复制代码 代码如下:
obj1.constructor===Guoyansi.prototype.constructor===Guoyansi

既然我们可以通过constructor来寻找构造器.因此我们就可以进一步完善上面的图了.

复制代码 代码如下:

 function GuoyansiEx(){}
             GuoyansiEx.prototype=new Guoyansi();
             console.log(GuoyansiEx.constructor===GuoyansiEx)//false

根据上图,上面的结果应该是true,但为什么是false呢?

现在做个分析.
GuoyansiEx的原型被Guoyansi的实例重写了,那么GuoyansiEx的原型中的constructor自然也是来自Guoyansi的实例.
而Guoyansi实例中的constructor又是来自Guoyansi.prototype.而Guoyansi.prototype没有被重写,
所以Guoyansi.prototype的constructor指向Guoyansi(构造函数);

根据以上分析得出下面的结论

复制代码 代码如下:
GuoyansiEx.constructor===Guoyansi.constructor===Guoyansi;

如果在开发过程中对于Constructor的指向要求非常精确的话,可以做如下处理.

复制代码 代码如下:

/**方法一:**/
 function Guoyansi(){}
             function GuoyansiEx(){}
             GuoyansiEx.prototype=new Guoyansi();
             GuoyansiEx.prototype.constructor=GuoyansiEx;//重置constructor指向.

复制代码 代码如下:

/**
            方法二
            **/
            function Guoyansi(){}
            function GuoyansiEx(){
                this.constructor=arguments.callee;
            }
            GuoyansiEx.prototype=new Guoyansi();

复制代码 代码如下:

/**
            方法三
            **/
            function Guoyansi(){}
            function GuoyansiEx(){
                this.constructor=GuoyansiEx;
            }
            GuoyansiEx.prototype=new Guoyansi();

三.看不见的原型有什么用呢?

看得见的原型链我们可以对他操作来完成我们的继承,那么这个看不见的原型链我们既看不见,又无法操作.要它有何用.
面向对象中继承有一个特性:相似性.子类与父类具有相似性.因此在子类中你是无法用delete删除从父类继承而来的成员.也就是说子类必须具有父类的特性.
为了维护这个特性,javascript在对象的内部产生了一条我们看不见的原型属性,并且不允许用户访问.这样,用户可以处于任何目的来修改constructor,
而不会破坏子类拥有父类的特性.
简而言之:内部原型是javascript的原型继承机制所需要的,而外部原型是用户实现继承所需要的.

四.火狐引擎SpiderMonkey中的__proto__

还是这段代码.

复制代码 代码如下:

function Guoyansi(){}
            Guoyansi.prototype.age=24;
            function GuoyansiEx(){}
            var obj1=new Guoyansi();
            GuoyansiEx.prototype=obj1;
            GuoyansiEx.prototype.constructor=GuoyansiEx;//重置constructor指向.
            var obj2=new GuoyansiEx();

我现在想要从obj开始向上访问父类Guoyansi的prototype的属性的age.
思路是这样的.
第一步:obj2====>obj2.constructor.prototype
第二部:obj2.constructor.prototype===>GuoyansiEx.prototype;
第三部:GuoyansiEx.prototype===>obj1;
第四部:obj1.constructor====>Guoyansi
第五部:Guoyansi.prototype.age

写成这这样:console.log(obj2.constructor.prototype.constructor.prototype.age)//24;
最终的结果是24.
最终的结果是24.可以正常执行,但是在好多书上说constructor修改后,级无法在找到父类中的原型了.不知道是怎么回事.

在火狐中提够了一种更加简洁的属性._proto_
SpiderMonkey中默认在任何创建的对象上添加了一个名为_proto_的属性,该属性指向构造器所用的原型.
其实就是我们上面提到的不可见的原型链,只不过是在这个地方变相的公开而已.
可以这样访问到age
console.log(obj2.__proto__.__proto__.age);//24
这样的确是成功的访问到了父类的原型属性,但是这个属性只适用于火狐,在其他浏览器中是会出错的.
在E5中对Object做出了扩展Object.getPrototypeOf(),可以访问到所有父类的原型了.

复制代码 代码如下:

function Guoyansi(){}
            Guoyansi.prototype.age=24;
            function GuoyansiEx(){}
            var obj1=new Guoyansi();
            GuoyansiEx.prototype=obj1;
            GuoyansiEx.prototype.constructor=GuoyansiEx;//重置constructor指向.
            var obj2=new GuoyansiEx();
            var proto=Object.getPrototypeOf(obj2);
            while(proto){
                console.log(proto.constructor);
                proto=Object.getPrototypeOf(proto);
            }
            console.log("object的原型"+proto);

结果是:GuoyansiEx
Guoyansi
Object
object的原型null

个人觉得这些应该算是javascript面向对象的精髓之一了.小伙伴们自己参考下,根据需求使用到自己的项目中去吧

相关文章

  • 使用js获取地址栏参数的方法推荐(超级简单)

    使用js获取地址栏参数的方法推荐(超级简单)

    下面小编就为大家带来一篇使用js获取地址栏参数的方法推荐(超级简单)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-06-06
  • JavaScript Function函数类型介绍

    JavaScript Function函数类型介绍

    在JS中,Function(函数)类型实际上是对象;每个函数都是Function类型的实例;而且都与其他引用类型一样具有属性和方法
    2015-04-04
  • JS实现监控微信小程序的原理

    JS实现监控微信小程序的原理

    这篇文章主要介绍了JS实现监控微信小程序的原理,本文通过实例代码相结合的形式给大家介绍的非常详细,需要的朋友可以参考下
    2018-06-06
  • layui获取选中行数据的实例讲解

    layui获取选中行数据的实例讲解

    今天小编就为大家分享一篇layui获取选中行数据的实例讲解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-08-08
  • 前端开发之便利店收银系统代码

    前端开发之便利店收银系统代码

    这篇文章主要介绍了社区便利店收银系统代码,使用前端初级开发者,代码很简单需要的朋友可以参考下
    2019-12-12
  • JS动态获取元素宽高的几种方式

    JS动态获取元素宽高的几种方式

    这篇文章主要介绍了js 动态获取元素宽高的几种方式,文章通过代码示例和图文结合的方式给大家介绍的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2024-09-09
  • JS字节数组转数字及数字转字节数组的方法

    JS字节数组转数字及数字转字节数组的方法

    本文将深入解析长整数与字节数组互转的技术原理,提供ES6(现代浏览器/Node.js)与ES5(兼容旧环境)两套实现方案,感兴趣的朋友一起看看吧
    2025-04-04
  • JavaScript 反射和属性赋值实例解析

    JavaScript 反射和属性赋值实例解析

    这篇文章主要介绍了JavaScript 反射和属性赋值实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-10-10
  • echarts设置暂无数据方法实例及遇到的问题

    echarts设置暂无数据方法实例及遇到的问题

    Echarts是百度旗下的一款开源的商业级数据可视化产品,具有丰富的图表类型,下面这篇文章主要给大家介绍了关于echarts设置暂无数据方法及遇到的问题的相关资料,需要的朋友可以参考下
    2022-12-12
  • js 判断文件类型并控制表单提交示例代码

    js 判断文件类型并控制表单提交示例代码

    判断文件类型控制表单提交这些都是在客户端实现的,下面有个不错的示例,感兴趣的朋友可以参考下
    2013-11-11

最新评论