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 相关文章推荐
js 方法实现返回多个数据的代码
Apr 30 Javascript
javascript Window及document对象详细整理
Jan 12 Javascript
jquery操作cookie插件分享
Jan 14 Javascript
为开发者准备的10款最好的jQuery日历插件
Feb 04 Javascript
Node.js入门教程:在windows和Linux上安装配置Node.js图文教程
Aug 14 Javascript
JQuery核心函数是什么及使用方法介绍
May 03 Javascript
Js动态设置rem来实现移动端字体的自适应代码
Oct 14 Javascript
JQueryEasyUI框架下的combobox的取值和绑定的方法
Jan 22 Javascript
javascript 中iframe高度自适应(同域)实例详解
May 16 Javascript
Vue自定义表单内容检查rules实例
Oct 30 Javascript
浅谈react路由传参的几种方式
Mar 23 Javascript
JavaScript实例 ODO List分析
Jan 22 Javascript
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
mysql From_unixtime及UNIX_TIMESTAMP及DATE_FORMAT日期函数
2010/03/21 PHP
PHP文章采集URL补全函数(FormatUrl)
2012/08/02 PHP
PHP定时执行任务实现方法详解(Timer)
2015/07/30 PHP
PHP实现json_decode不转义中文的方法
2017/05/20 PHP
解决laravel5.4下的group by报错的问题
2019/10/16 PHP
Aster vs Newbee BO5 第三场2.19
2021/03/10 DOTA
JS文本框追加多个下拉框的值的简单实例
2013/07/12 Javascript
jquery制作属于自己的select自定义样式
2015/11/23 Javascript
基于jquery实现简单的手风琴特效
2015/11/24 Javascript
js面向对象的写法
2016/02/19 Javascript
AngularJS操作键值对象类似java的hashmap(填坑小结)
2016/11/12 Javascript
详解Nodejs之静态资源处理
2017/06/05 NodeJs
详解vue-cli 快速搭建单页应用之遇到的问题及解决办法
2018/03/01 Javascript
vue2.0路由切换后页面滚动位置不变BUG的解决方法
2018/03/14 Javascript
不使用JavaScript实现菜单的打开和关闭效果demo
2018/05/01 Javascript
Nodejs中获取当前函数被调用的行数及文件名详解
2018/12/12 NodeJs
js实现简单掷骰子效果
2019/10/24 Javascript
如何解决vue在ios微信"复制链接"功能问题
2020/03/26 Javascript
js实现菜单跳转效果
2020/12/11 Javascript
iview实现动态表单和自定义验证时间段重叠
2021/01/10 Javascript
[04:19]完美世界携手游戏风云打造 卡尔工作室模型介绍篇
2013/04/24 DOTA
python之yield表达式学习
2014/09/02 Python
Python中处理字符串之isalpha()方法的使用
2015/05/18 Python
解决python删除文件的权限错误问题
2018/04/24 Python
Python处理session的方法整理
2019/08/29 Python
python3爬虫中多线程的优势总结
2020/11/24 Python
详解如何获取localStorage最大存储大小的方法
2020/05/21 HTML / CSS
AmazeUI导航的示例代码
2020/08/14 HTML / CSS
史上最全面的Java面试题汇总!
2015/02/03 面试题
关于打架的检讨书
2014/01/17 职场文书
旅游网创业计划书
2014/01/31 职场文书
对孩子的寄语
2014/04/09 职场文书
家庭贫困证明
2014/09/23 职场文书
教师见习总结范文
2015/06/23 职场文书
2016高中社会实践心得体会范文
2016/01/14 职场文书
Mysql中常用的join连接方式
2022/05/11 MySQL