javascript 原型链维护和继承详解


Posted in Javascript onNovember 26, 2014

一.两个原型

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

//构造器声明

        function Guoyansi(){ }

        function GuoyansiEx(){}

        //原型继承

         GuoyansiEx.prototype=new Guoyansi();

       //创建对象

       var g1=new GuoyansiEx();

       var g2=new GuoyansiEx();

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

javascript 原型链维护和继承详解

二.原型的维护

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

function Guoyansi(){ }

var obj1=new Guoyansi();

console.log(obj1.constructor===Guoyansi);//true

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

obj1.constructor===Guoyansi.prototype.constructor===Guoyansi

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

javascript 原型链维护和继承详解

 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面向对象的精髓之一了.小伙伴们自己参考下,根据需求使用到自己的项目中去吧

Javascript 相关文章推荐
JS对URL字符串进行编码/解码分析
Oct 25 Javascript
jQuery移动和复制dom节点实用DOM操作案例
Dec 17 Javascript
表单验证的完整应用案例探讨
Mar 29 Javascript
改变状态栏文字的js代码
Jun 13 Javascript
JS实现的简单鼠标跟随DiV层效果完整实例
Oct 31 Javascript
基于javascript实现窗口抖动效果
Jan 03 Javascript
JS简单设置下拉选择框默认值的方法
Aug 20 Javascript
微信小程序开发教程-手势解锁实例
Jan 06 Javascript
WebView启动支付宝客户端支付失败的问题小结
Jan 11 Javascript
使用ionic(选项卡栏tab) icon(图标) ionic上拉菜单(ActionSheet) 实现通讯录界面切换实例代码
Oct 20 Javascript
Vue异步加载about组件
Oct 31 Javascript
vue 解决无法对未定义的值,空值或基元值设置反应属性报错问题
Jul 31 Javascript
jquery提示效果实例分析
Nov 25 #Javascript
jQuery操作cookie方法实例教程
Nov 25 #Javascript
JavaScript常用验证函数实例汇总
Nov 25 #Javascript
JavaScript导出Excel实例详解
Nov 25 #Javascript
JS倒计时代码汇总
Nov 25 #Javascript
jquery中push()的用法(数组添加元素)
Nov 25 #Javascript
Jquery焦点图实例代码
Nov 25 #Javascript
You might like
php5 apache 2.2 webservice 创建与配置(java)
2011/01/27 PHP
基于PHP导出Excel的小经验 完美解决乱码问题
2013/06/10 PHP
PHP数据库操作之基于Mysqli的数据库操作类库
2014/04/19 PHP
PHP5.3与5.5废弃与过期函数整理汇总
2014/07/10 PHP
PHP中file_exists函数不支持中文名的解决方法
2014/07/26 PHP
PHP基于PDO扩展操作mysql数据库示例
2018/12/24 PHP
php+laravel依赖注入知识点总结
2019/11/04 PHP
javascipt:filter过滤介绍及使用
2014/09/10 Javascript
html的DOM中document对象forms集合用法实例
2015/01/21 Javascript
Javascript将数字转化成为货币格式字符串
2016/06/22 Javascript
页面间固定参数,通过cookie传值的实现方法
2017/05/31 Javascript
基于Vuejs的搜索匹配功能实现方法
2018/03/03 Javascript
通过vue-router懒加载解决首次加载时资源过多导致的速度缓慢问题
2018/04/08 Javascript
NodeJS搭建HTTP服务器的实现步骤
2018/10/12 NodeJs
小程序实现自定义导航栏适配完美版
2019/04/02 Javascript
微信小程序非跳转式组件授权登录的方法示例
2019/05/22 Javascript
vue开发chrome插件,实现获取界面数据和保存到数据库功能
2020/12/01 Vue.js
在 Django/Flask 开发服务器上使用 HTTPS
2014/07/03 Python
Python中的各种装饰器详解
2015/04/11 Python
python实现二维码扫码自动登录淘宝
2016/12/27 Python
对python的unittest架构公共参数token提取方法详解
2018/12/17 Python
python导包的几种方法(自定义包的生成以及导入详解)
2019/07/15 Python
python opencv实现证件照换底功能
2019/08/19 Python
Django关于admin的使用技巧和知识点
2020/02/10 Python
matplotlib 多个图像共用一个colorbar的实现示例
2020/09/10 Python
canvas学习笔记之绘制简单路径
2019/01/28 HTML / CSS
凯特王妃父母建立的派对用品网站:Party Pieces
2017/05/28 全球购物
Theo + George官方网站:都柏林时尚品牌
2019/04/08 全球购物
德国购买踏板车网站:Microscooter
2019/10/14 全球购物
extern在函数声明中是什么意思
2014/01/19 面试题
关联、聚合(Aggregation)以及组合(Composition)的区别
2012/02/29 面试题
linux面试题参考答案(9)
2015/01/07 面试题
外贸销售员求职的自我评价
2013/11/23 职场文书
2014年党员承诺书范文
2014/05/20 职场文书
个人查摆问题自查报告
2014/10/16 职场文书
优秀家长事迹材料(2016推荐版)
2016/02/29 职场文书