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 相关文章推荐
简明json介绍
Sep 28 Javascript
Web开发者必备的12款超赞jQuery插件
Dec 03 Javascript
js 静态动态成员 and 信息的封装和隐藏
May 29 Javascript
关于JS控制代码暂停的实现方法分享
Oct 11 Javascript
如何使用jQUery获取选中radio对应的值(一句代码)
Jun 03 Javascript
Node.js中的事件驱动编程详解
Aug 16 Javascript
基于jquery实现图片上传本地预览功能
Jan 08 Javascript
原生javascript实现匀速运动动画效果
Feb 26 Javascript
浅谈Node.js:Buffer模块
Dec 05 Javascript
jQuery File Upload文件上传插件使用详解
Dec 06 Javascript
妙用缓存调用链实现JS方法的重载
Apr 30 Javascript
微信上传视频文件提示(推荐)
Nov 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
Protoss热键控制
2020/03/14 星际争霸
php笔记之:文章中图片处理的使用
2013/04/26 PHP
Yii2单元测试用法示例
2016/11/12 PHP
javascript实现unicode和字符的互相转换
2007/07/18 Javascript
Javascript和Ajax中文乱码吐血版解决方案
2009/12/21 Javascript
JQuery Study Notes 学习笔记(一)
2010/08/04 Javascript
一行代码实现纯数据json对象的深度克隆实现思路
2013/01/09 Javascript
JS.elementGetStyle(element, style)应用示例
2013/09/24 Javascript
javascript获取xml节点的最大值(实现代码)
2013/12/11 Javascript
Angular用来控制元素的展示与否的原生指令介绍
2015/01/07 Javascript
Bootstrap幻灯片轮播图支持触屏左右手势滑动的实现方法
2016/10/13 Javascript
NodeJS实现客户端js加密
2017/01/09 NodeJs
原生js实现水平方向无缝滚动
2017/01/10 Javascript
Angular项目从新建、打包到nginx部署全过程记录
2017/12/09 Javascript
webpack项目轻松混用css module的方法
2018/06/12 Javascript
手把手教你用Node.js爬虫爬取网站数据的方法
2018/07/05 Javascript
用node撸一个监测复联4开售短信提醒的实现代码
2019/04/10 Javascript
基于JS实现计算24点算法代码实例解析
2020/07/23 Javascript
Python多进程通信Queue、Pipe、Value、Array实例
2014/11/21 Python
在Python中使用swapCase()方法转换大小写的教程
2015/05/20 Python
python实现树形打印目录结构
2018/03/29 Python
Linux-ubuntu16.04 Python3.5配置OpenCV3.2的方法
2018/04/02 Python
在Python3 numpy中mean和average的区别详解
2019/08/24 Python
Django模板语言 Tags使用详解
2019/09/09 Python
如何在Django中使用聚合的实现示例
2020/03/23 Python
python3 配置logging日志类的操作
2020/04/08 Python
python统计mysql数据量变化并调用接口告警的示例代码
2020/09/21 Python
介绍一下EJB的分类及其各自的功能及应用
2016/08/23 面试题
医院护士的求职信范文
2013/12/26 职场文书
应届毕业生自我鉴定范文
2013/12/27 职场文书
网络程序员自荐信
2014/01/25 职场文书
人事科岗位职责范本
2014/03/02 职场文书
实习护士自荐信
2014/06/21 职场文书
小学老师对学生的评语
2014/12/29 职场文书
2016感恩母亲节校园广播稿
2015/12/17 职场文书
无线电通信名词解释
2022/02/18 无线电