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漂浮广告实现代码
Aug 15 Javascript
JS HTML5拖拽上传图片预览
Jul 18 Javascript
jquery层级选择器(匹配父元素下的子元素实现代码)
Sep 05 Javascript
setTimeout学习小结
Feb 08 Javascript
ES6 javascript中class类的get与set用法实例分析
Oct 30 Javascript
Vue的事件响应式进度条组件实例详解
Feb 04 Javascript
vue引入js数字小键盘的实现代码
May 14 Javascript
layui table表格数据的新增,修改,删除,查询,双击获取行数据方式
Nov 14 Javascript
JavaScript设计模式之门面模式原理与实现方法分析
Mar 09 Javascript
精读《Vue3.0 Function API》
May 20 Javascript
深入了解JS之作用域和闭包
Jun 16 Javascript
JS实现拖拽元素时与另一元素碰撞检测
Aug 27 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写的简单数字验证码实例
2017/05/23 PHP
JavaScript 匿名函数(anonymous function)与闭包(closure)
2011/10/04 Javascript
jQuery 瀑布流 绝对定位布局(二)(延迟AJAX加载图片)
2012/05/23 Javascript
jQuery实现点击标题输入详细信息
2013/04/16 Javascript
JavaScript中的迭代器和生成器详解
2014/10/29 Javascript
jquery性能优化高级技巧
2015/08/24 Javascript
浅谈JavaScript的内置对象和浏览器对象
2016/06/03 Javascript
JavaScript中如何使用cookie实现记住密码功能及cookie相关函数介绍
2016/11/10 Javascript
jQuery实现多张图片上传预览(不经过后端处理)
2017/04/29 jQuery
Node.js  事件循环详解及实例
2017/08/06 Javascript
input file样式修改以及图片预览删除功能详细概括(推荐)
2017/08/17 Javascript
jQuery Datatables表头不对齐的解决办法
2017/11/27 jQuery
vue3.0 CLI - 2.1 -  component 组件入门教程
2018/09/14 Javascript
JavaScript中callee和caller的区别与用法实例分析
2019/06/28 Javascript
基于layPage插件实现两种分页方式浅析
2019/07/27 Javascript
[52:06]完美世界DOTA2联赛决赛日 Inki vs LBZS 第一场 11.08
2020/11/10 DOTA
wxPython窗口中文乱码解决方法
2014/10/11 Python
Python实现遍历windows所有窗口并输出窗口标题的方法
2015/03/13 Python
python执行scp命令拷贝文件及文件夹到远程主机的目录方法
2019/07/08 Python
pytorch 批次遍历数据集打印数据的例子
2019/12/30 Python
tensorflow 2.1.0 安装与实战教程(CASIA FACE v5)
2020/06/30 Python
详解Python利用configparser对配置文件进行读写操作
2020/11/03 Python
python自动生成证件号的方法示例
2021/01/14 Python
表单button的outline在firefox浏览器下的问题
2012/12/24 HTML / CSS
使用HTML5 Canvas API中的clip()方法裁剪区域图像
2016/03/25 HTML / CSS
纽约香氛品牌:NEST Fragrance
2018/10/15 全球购物
质量承诺书范文
2014/03/27 职场文书
环卫工人先进事迹材料
2014/06/02 职场文书
老兵退伍标语
2014/10/07 职场文书
2014年扶贫工作总结
2014/11/18 职场文书
房地产公司财务总监岗位职责
2015/04/03 职场文书
领导新年致辞2016
2015/07/29 职场文书
践行三严三实心得体会(2016推荐篇)
2016/01/06 职场文书
《7的乘法口诀》教学反思
2016/02/18 职场文书
浅谈golang package中init方法的多处定义及运行顺序问题
2021/05/06 Golang
微信小程序实现轮播图指示器
2022/06/25 Javascript