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 相关文章推荐
ext实现完整的登录代码
Aug 08 Javascript
用Javascript实现锚点(Anchor)间平滑跳转
Sep 08 Javascript
JavaScript 盒模型 尺寸深入理解
Dec 31 Javascript
jquerydom对象的事件隐藏显示和对象数组示例
Dec 10 Javascript
JS实现获取剪贴板内容的方法
Jun 21 Javascript
JS实现字符串转驼峰格式的方法
Dec 16 Javascript
浅谈pc端rem字体设置的问题
Aug 03 Javascript
利用ECharts.js画K线图的方法示例
Jan 10 Javascript
Vue中computed与methods的区别详解
Mar 24 Javascript
jQuery实现table表格信息的展开和缩小功能示例
Jul 21 jQuery
Vue自定义属性实例分析
Feb 23 Javascript
详解Vue-cli3.X使用px2rem遇到的问题
Aug 09 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下intval()和(int)转换使用与区别
2008/07/18 PHP
PHP 文件编程综合案例-文件上传的实现
2013/07/03 PHP
详谈PHP文件目录基础操作
2014/11/11 PHP
php自动载入类用法实例分析
2016/06/24 PHP
php自定义函数br2nl实现将html中br换行符转换为文本输入中换行符的方法【与函数nl2br功能相反】
2017/02/17 PHP
PHP利用Cookie设置用户30分钟未操作自动退出功能
2017/07/03 PHP
fromCharCode和charCodeAt 方法
2006/12/27 Javascript
Javascript 实用小技巧
2010/04/07 Javascript
JavaScript面向对象之Prototypes和继承
2012/07/12 Javascript
jQuery中:input选择器用法实例
2015/01/03 Javascript
jQuery中inArray方法注意事项分析
2016/01/25 Javascript
jQuery插件HighCharts实现2D柱状图、折线图的组合多轴图效果示例【附demo源码下载】
2017/03/09 Javascript
AngularJS实现动态添加Option的方法
2017/05/17 Javascript
微信小程序利用co处理异步流程的方法教程
2017/05/20 Javascript
ReactNative实现图片上传功能的示例代码
2017/07/11 Javascript
bootstrap select下拉搜索插件使用方法详解
2017/11/23 Javascript
10分钟上手vue-cli 3.0 入门介绍
2018/04/04 Javascript
jQuery插件实现的日历功能示例【附源码下载】
2018/09/07 jQuery
python删除列表内容
2015/08/04 Python
Win7下Python与Tensorflow-CPU版开发环境的安装与配置过程
2018/01/04 Python
Python解析命令行读取参数--argparse模块使用方法
2018/01/23 Python
基于python实现蓝牙通信代码实例
2019/11/19 Python
用python对oracle进行简单性能测试
2020/12/05 Python
HTML5 Canvas阴影使用方法实例演示
2013/08/02 HTML / CSS
html5使用canvas画空心圆与实心圆
2014/12/15 HTML / CSS
html5 外链式实现加减乘除的代码
2019/09/04 HTML / CSS
一名女生的自荐信
2013/12/08 职场文书
大学校园活动策划书
2014/02/04 职场文书
新教师工作感言
2014/02/16 职场文书
校优秀毕业生主要事迹
2014/05/26 职场文书
机械加工与数控专业自荐书
2014/06/04 职场文书
助人为乐好少年事迹材料
2014/08/18 职场文书
电力培训学习心得体会
2016/01/11 职场文书
《海上日出》教学反思
2016/02/23 职场文书
责任书格式
2019/04/18 职场文书
PyCharm 安装与使用配置教程(windows,mac通用)
2021/05/12 Python