JS原型链 详解及示例代码


Posted in Javascript onSeptember 06, 2016

前言

在 segmentfault 上看到这样一道题目:

var F = function(){};
Object.prototype.a = function(){};
Function.prototype.b = function(){};
var f = new F();

问:f 能取到a,b吗?原理是什么?

乍一看真的有点懵,仔细研究了一下,发现还是对原型理解不透彻,所以总结一篇,填个洞~

Function和Object

在解题之前,先再说说 原型、原型链,以及 Function 和 Object 的关系,这也是本文的重点。

原型

在创建一个函数的时候,会自动为其创建一个原型对象,可以通过函数的prototype属性访问到。

创建一个构造函数的实例对象,该实例对象内部将包含一个指针(内部属性),指向构造函数的原型对象。ECMA-262 第5版中管这个指针叫[[prototype]]。虽然在脚本中没有标准的方式访问[[prototype]],但Firefox、 Safari、 Chrome在每个对象上都支持一个属性 __proto__,用于访问其构造函数的原型对象。

重要的事情再说一遍:
构造函数通过 prototype 属性访问原型对象。
实例对象通过 [[prototype]] 内部属性访问原型对象,浏览器实现了 _proto_ 属性用于实例对象访问原型对象。

var F = function () {};
var f = new F();
// 假设F的原型对象是 p, 则
// F.prototype === p;
// f.__proto__ === p;

再重复一遍。。prototype说的是构造函数和原型对象之间的关系,__proto__说的是实例对象和原型对象之间的关系。

原型链

类 A继承B,B继承C……其实就是A的原型对象中有指针指向B的原型对象,而B的原型对象中有指针指向C的原型对象……注意是原型对象之间的联系,A B C 这三个构造函数之间并没什么关系,所以才称为“原型链”吧~

假设a是A的实例对象,则 a 的原型链为下图中紫色线条所示,橙色线条连接了构造函数和其原型对象。

JS原型链 详解及示例代码

由图可以看出,原型链的末端是Object.prototype.__proto__即null。当查找a的某个属性或方法时,首先查找a自身有没有,没有则沿着原型链一直查找,直到找到或者最后到null返回undefined。

Function 和 Object

Function 和 Object 之间的关系有点绕:

Object 是构造函数,既然是函数,那么就是Function的实例对象;Function是构造函数,但Function.prototype是对象,既然是对象,那么就是Object的实例对象。

一切对象都是Object的实例,一切函数都是Function的实例。

Object是Function的实例,而Function.prototype是Object的实例。

二者的关系如下图所示。

JS原型链 详解及示例代码

可见,Object作为构造函数,它有 prototype 属性指向 Object.prototype , 作为实例对象, 它有 Object.__proto__ 指向Function.prototype。Function是构造函数,它有prototype属性指向Function.prototype,而Function是函数,从而也是Function的实例,所以它有Function.__proto__指向Function.prototype,从而 Function.__proto__ === Function.prototype 为 true。

可在Chrome控制台下进行验证,如图。

JS原型链 详解及示例代码

原题解析

解决原型链问题最好的办法就是画图了,经过前面的分析,这个图画起来应该不成问题,如下~

JS原型链 详解及示例代码

f 的原型链为蓝色线所画,所以 f 可以访问到 a , 不能访问到 b 。

如果不画图,乍一看,可能会觉得f 可以访问到 b,那是可能跟我一样误认为F.prototype指向Function.prototype,但其实F.prototype是对象而不是函数,所以它的原型对象不会是 Function.prototype。

所以,原型链问题一应要画图啊~

原题扩展

在上题中,f 只能访问 a,不能访问 b 。但 F 既可以访问 a ,又可以访问 b。如果把题修改成下面的样子, F.b()的结果是什么呢?为什么呢?可以想一下哦~

var F = function(){};
Object.prototype.a = function(){};
Function.prototype.b = function(){ console.log('F.__proto__') };
F.prototype.b = function (){console.log('F.prototype');};

总结

读到这里,有没有发现函数一个比较特殊的地方?

一般的对象,只有一个__proto__属性用于访问其构造函数的原型对象,而对于函数来说,它既是函数又是对象。

作为函数,它生来就有prototype属性指向其原型对象函数名.prototype。

作为Function的实例对象,它有__proto__属性指向Function.prototype

通常,这两个属性是指向两个对象的,但Function的这两个属性指向相同,都指向Function.prototype。

对于函数 A( ) 来说,A.prototype 中的方法是供其实例对象调用的,自己并不会用;当A 作为实例运行时,调用的是A.__proto__ 中的方法。也就是说,作为构造函数使用时,走的是A.prototype这条链,方法、属性赋给其实例;作为对象使用时,走的是A.__proto__这条链。在不同的场景下,分清它的身份就不会错了。

整篇下来,感觉自己说的也比较絮叨……不足之处,还请各位指正~ 至于题目,真的不知道该叫什么好。。

愿本文能带给坚持看完的你一些收获~ ^_^

谢谢大家对本站的支持,后续继续更新相关资料,帮助大家学习了解这部分知识!

Javascript 相关文章推荐
capacityFixed 基于jquery的类似于新浪微博新消息提示的定位框
May 24 Javascript
Knockout text绑定DOM的使用方法
Nov 15 Javascript
JavaScript加入收藏夹功能(兼容IE、firefox、chrome)
May 05 Javascript
Jquery中CSS选择器用法分析
Feb 10 Javascript
js控制页面的全屏展示和退出全屏显示的方法
Mar 10 Javascript
JQuery 在文档中查找指定name的元素并移除的实现方法
May 19 Javascript
jQuery的层级查找方式分析
Jun 16 Javascript
Node.js实现注册邮箱激活功能的方法示例
Mar 23 Javascript
Vuepress 搭建带评论功能的静态博客的实现
Feb 17 Javascript
一文快速了解JQuery中的AJAX
May 31 jQuery
基于vue实现圆形菜单栏组件
Jul 05 Javascript
vue实现水波涟漪效果的点击反馈指令
May 31 Vue.js
JavaScript中push(),join() 函数 实例详解
Sep 06 #Javascript
jquery实现全选、不选、反选的两种方法
Sep 06 #Javascript
fullpage.js全屏滚动插件使用实例
Sep 06 #Javascript
AngularJS  $on、$emit和$broadcast的使用
Sep 05 #Javascript
JavaScript中最容易混淆的作用域、提升、闭包知识详解(推荐)
Sep 05 #Javascript
Vuejs第六篇之Vuejs与form元素实例解析
Sep 05 #Javascript
Vue表单实例代码
Sep 05 #Javascript
You might like
php将数据库导出成excel的方法
2010/05/07 PHP
php守护进程 加linux命令nohup实现任务每秒执行一次
2011/07/04 PHP
PHPThumb PHP 图片缩略图库
2012/03/11 PHP
tp5框架前台无限极导航菜单类实现方法分析
2020/03/29 PHP
js 与或运算符 || && 妙用
2009/12/09 Javascript
jQuery代码优化 遍历篇
2011/11/01 Javascript
javascript实现俄罗斯方块游戏的思路和方法
2015/04/27 Javascript
jQuery的选择器中的通配符[id^='code']或[name^='code']及jquery选择器总结
2015/12/24 Javascript
详解AngularJS中的http拦截
2016/02/09 Javascript
BootStrap智能表单demo示例详解
2016/06/13 Javascript
JS+html5 canvas实现的简单绘制折线图效果示例
2017/03/13 Javascript
ES6新特性一: let和const命令详解
2017/04/20 Javascript
Node.js中你不可不精的Stream(流)
2018/06/08 Javascript
vue.js轮播图组件使用方法详解
2018/07/03 Javascript
Redux实现组合计数器的示例代码
2018/07/04 Javascript
vue-cli配置环境变量的方法
2018/07/09 Javascript
electron实现静默打印的示例代码
2019/08/12 Javascript
微信小程序实现Swiper轮播图效果
2019/11/22 Javascript
vue中解决微信html5原生ios虚拟键返回不刷新问题
2020/10/20 Javascript
python技能之数据导出excel的实例代码
2017/08/11 Python
python中for循环输出列表索引与对应的值方法
2018/11/07 Python
Python实现定期检查源目录与备份目录的差异并进行备份功能示例
2019/02/27 Python
pytorch 获取层权重,对特定层注入hook, 提取中间层输出的方法
2019/08/17 Python
Python调用Windows命令打印文件
2020/02/07 Python
Jupyter notebook 远程配置及SSL加密教程
2020/04/14 Python
python简单实现最大似然估计&scipy库的使用详解
2020/04/15 Python
世界上最大的在线学习和教学市场:Udemy
2017/11/08 全球购物
SKECHERS官方旗舰店:美国舒适运动休闲品牌
2017/12/22 全球购物
C/C++ 笔试、面试题目大汇总
2015/11/21 面试题
学校司机岗位职责
2013/11/14 职场文书
办公室员工岗位工作职责
2014/03/10 职场文书
客户经理竞聘演讲稿
2014/05/15 职场文书
建筑安全生产目标责任书
2014/07/23 职场文书
平安工地汇报材料
2014/08/19 职场文书
党章培训心得体会
2014/09/04 职场文书
离婚协议书格式
2015/01/26 职场文书