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 相关文章推荐
在IE模态窗口中自由查看HTML源码的方法
Mar 08 Javascript
js wmp操作代码小结(音乐连播功能)
Nov 08 Javascript
如何用JavaScript实现动态修改CSS样式表
May 20 Javascript
JS中with的替代方法与String中的正则方法详解
Dec 23 Javascript
原生js实现简单的Ripple按钮实例代码
Mar 24 Javascript
socket.io学习教程之基础介绍(一)
Apr 29 Javascript
vue的Virtual Dom实现snabbdom解密
May 03 Javascript
Node.js利用js-xlsx处理Excel文件的方法详解
Jul 05 Javascript
轻松玩转BootstrapTable(后端使用SpringMVC+Hibernate)
Sep 06 Javascript
Express本地测试HTTPS的示例代码
Jun 06 Javascript
ES6 Promise对象概念及用法实例详解
Oct 15 Javascript
解决vant title-active-color与title-inactive-color不生效问题
Nov 03 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
PHP中利用substr_replace将指定两位置之间的字符替换为*号
2011/01/27 PHP
比较时间段一与时间段二是否有交集的php函数
2011/05/31 PHP
php URL跳转代码 减少外链
2011/06/25 PHP
PHP中CURL方法curl_setopt()函数的参数分享
2013/01/19 PHP
基于PHP Socket配置以及实例的详细介绍
2013/06/13 PHP
php number_format() 函数通过千位分组来格式化数字的实现代码
2013/08/06 PHP
php对二维数组进行排序的简单实例
2013/12/19 PHP
PHP防范SQL注入的具体方法详解(测试通过)
2014/05/09 PHP
PHP利用MySQL保存session的实现思路及示例代码
2014/09/09 PHP
innerHTML,outerHTML,innerTEXT三者之间的区别
2007/01/28 Javascript
jQuery 版本的文本输入框检查器Input Check
2009/07/09 Javascript
IE6下CSS图片缓存问题解决方法
2010/12/09 Javascript
jquery 插件学习(二)
2012/08/06 Javascript
基于jquery的滚动条滚动固定div(附演示下载)
2012/10/29 Javascript
jQuery获得内容和属性示例代码
2014/01/16 Javascript
javascript不同类型数据之间的运算的转换方法
2014/02/13 Javascript
javascript基础语法学习笔记
2016/01/04 Javascript
jackson解析json字符串,首字母大写会自动转为小写的方法
2017/12/22 Javascript
让axios发送表单请求形式的键值对post数据的实例
2018/08/11 Javascript
node.js基于socket.io快速实现一个实时通讯应用
2019/04/23 Javascript
微信小程序 授权登录详解(附完整源码)
2019/08/23 Javascript
Python简单实现安全开关文件的两种方式
2016/09/19 Python
浅谈编码,解码,乱码的问题
2016/12/30 Python
详解如何使用Python编写vim插件
2017/11/28 Python
一篇文章快速了解Python的GIL
2018/01/12 Python
python 内置函数汇总详解
2019/09/16 Python
Pandas —— resample()重采样和asfreq()频度转换方式
2020/02/26 Python
如何基于Python爬取隐秘的角落评论
2020/07/02 Python
美国旅游网站:Tours4Fun
2017/02/17 全球购物
国旗下演讲稿
2014/05/08 职场文书
公司年终奖分配方案
2014/06/16 职场文书
乡镇领导班子四风对照检查材料
2014/09/27 职场文书
教师批评与自我批评
2014/10/15 职场文书
业务员岗位职责
2015/02/03 职场文书
黑白记忆观后感
2015/06/18 职场文书
八年级作文之友谊
2019/12/02 职场文书