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 相关文章推荐
JavaScript 快捷键设置实现代码
Mar 13 Javascript
Javascript 面向对象 继承
May 13 Javascript
PHP abstract与interface之间的区别
Nov 11 Javascript
JavaScript Array对象扩展indexOf()方法
May 09 Javascript
比较常见的javascript中定义函数的区别
Nov 09 Javascript
仿Angular Bootstrap TimePicker创建分钟数-秒数的输入控件
Jul 01 Javascript
jQuery学习笔记之回调函数
Aug 15 Javascript
JavaScript中的函数申明、函数表达式、箭头函数
Dec 06 Javascript
Jquery+AJAX实现无刷新上传并重命名文件操作示例【PHP后台接收】
May 29 jQuery
Vue实现简单购物车功能
Dec 13 Vue.js
react中的DOM操作实现
Jun 30 Javascript
vue 数字翻牌器动态加载数据
Apr 20 Vue.js
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
Flash空降上海 化身大魔王接受挑战
2020/03/02 星际争霸
Php 构造函数construct的前下划线是双的_
2009/12/08 PHP
php守护进程 加linux命令nohup实现任务每秒执行一次
2011/07/04 PHP
Symfony2获取web目录绝对路径、相对路径、网址的方法
2016/11/14 PHP
详解PHP安装mysql.so扩展的方法
2016/12/31 PHP
PHP自定义函数实现assign()数组分配到模板及extract()变量分配到模板功能示例
2018/05/23 PHP
jQuery中文入门指南,翻译加实例,jQuery的起点教程
2007/01/13 Javascript
一个判断email合法性的函数[非正则]
2008/12/09 Javascript
jQuery中的常用事件总结
2009/12/27 Javascript
在每个匹配元素的外部插入新元素的方法
2013/12/20 Javascript
JavaScript三元运算符的多种使用技巧
2015/04/16 Javascript
JavaScript的面向对象编程基础
2015/08/13 Javascript
noty ? jQuery通知插件全面解析
2016/05/18 Javascript
带有定位当前位置的百度地图前端web api实例代码
2016/06/21 Javascript
JavaScript 实现的checkbox经典实例分享
2016/10/16 Javascript
bootstrap table分页模板和获取表中的ID方法
2017/01/10 Javascript
jquery拼接ajax 的json和字符串拼接的方法
2017/03/11 Javascript
js实现自定义进度条效果
2017/03/15 Javascript
vue自定义tap指令及tap事件的实现
2018/09/18 Javascript
Node 搭建一个静态资源服务器的实现
2019/05/20 Javascript
[14:00]DOTA2国际邀请赛史上最长大战 赛后专访B神
2013/08/10 DOTA
[01:35]2018完美盛典章节片——共竞
2018/12/17 DOTA
Python实现的快速排序算法详解
2017/08/01 Python
python 时间信息“2018-02-04 18:23:35“ 解析成字典形式的结果代码详解
2018/04/19 Python
python实现将一个数组逆序输出的方法
2018/06/25 Python
tensorflow-gpu安装的常见问题及解决方案
2020/01/20 Python
浅析PyCharm 的初始设置(知道)
2020/10/12 Python
python调用百度API实现人脸识别
2020/11/17 Python
python 中 .py文件 转 .pyd文件的操作
2021/03/04 Python
奇怪的鱼:Weird Fish
2018/03/18 全球购物
英国儿童设计师服装和玩具购物网站:Zac & Lulu
2020/10/19 全球购物
程序员机试试题汇总
2012/03/07 面试题
自动化毕业生专业自荐书范文
2014/02/04 职场文书
三好学生演讲稿范文
2014/04/26 职场文书
河童之夏观后感
2015/06/11 职场文书
Python实现滑雪小游戏
2021/09/25 Python