前言

原型链虽然概念上比较简单,用了奇怪的姿势模拟了继承的功能性,但是在整个Javascript的世界里面,它的的关系错综复杂,很容易被它们之间的关系绕进去

  • __ proto __[[prototype]]prototype傻傻分不清楚,
  • Object创建了Function,还是Function创建了Object

所以我想要从头梳理一遍,让大家(自己)更清晰的看清原型链。

开始之前

回顾我们学习Javascript的时候,一定听说过一句话

一切皆对象

这句话说的非常准确,但是有一点例外,就是primitive基础类型值,不过在使用其方法的时候也会自动被包装成对象,不过这是题外之话。

这里你肯定有一个疑问,那么我们执行的function是对象吗?

答案是肯定的,以下我会将函数称为函数对象

说完这个,我们正式开始吧

正文

最原始的原型结构

const obj = {};

在Javscript中如果我们这样声明一个对象obj,那么它的原型结构如上图。

Javascript它通过Object()构造函数创建了obj,并且创建的obj都有一个隐藏内置属性[[prototype]]并把它指向Object.prototype属性,Object.prototype的constructor指回构造函数Object(),而Object.prototype之中也有一个[[prototype]],它指向了虚无null

而这个Object.prototype是所有原型链(prototype chain)的终点

记住这个结构,这个结构可以推导出所有的原型链,它是Javascript世界的基本结构!

逐渐复杂的原型

我们除了上面说的第一种创建对象的方式还有另外一种,就是通过构造函数的方式来创建

function Bar() {}
const foo = new Bar();

类比上面结构,我们得出以下结构

上面提到,Object.prototype是所有原型链的终点,而Bar.prototype就是一个普通的对象,那么这个?就是Object.prototype, 结合第一张图,得到以下的图

到此我们创建最基础的原型链(prototype chain),所有的原型链(prototype chain)都是基于这个结构不断累加,不过现在只说清楚了普通的对象,Javascript的世界一切皆对象,函数对象又是谁创建的?不过在说这个之前我们先把一些概念说清楚。

__ proto __[[prototype]]prototype三姐妹

现在prototype[[prototype]]已经浮出水面,加上__proto__就来说说它们之间的区别

[[prototype]]它是每个Javascript对象都会有的隐藏内置属性,为的都是能让每个对象都能顺着它的prototype chain往上找,也就是每个对象与生俱来的能力,它的终点是null

__proto__ 是一个非正规的访问[[prototype]]属性的方式,本质上是一个定义在Object.prototype上面的属性__proto__,通过getter,setter方法操作访问。obj本身没有__proto__ 没有这个属性,但是通过[[prototype]]我们访问到了Object.prototype上面的__proto__(通过this绑定,我们知道了是obj的),所以获取到了[[prototype]]的对象。 不过现在并不推荐这么做,而是推荐使用Object.getPrototypeOf(obj)Object.setPrototypeOf(obj, parent)来访问操作__proto__。

prototype它只存在在函数对象上面的一个正常公开的属性,Bar.hasOwnProperty('prototype')这个可以证明, 不过函数对象自然也有一个[[prototype]],它指向哪?我们先按下不表。

先通过代码验证一下,刚刚说过的结构

const obj = {};
function Bar() {}
const foo = new Bar(); obj.__proto__.__proto__ // null
obj.__proto__ === Object.prototype /// true
bar.prototype.__proto__ === obj.__proto__ //true
bar.prototype.__proto__.__proto__ // nullobj.__proto__ === Object.getPrototypeOf(obj) // true
Object.getPrototypeOf(obj) === Bar.prototype // false
Object.getPrototypeOf(obj) === Bar.prototype.__proto__ // truefoo.__proto__ === Bar.prototype // true
foo.prototype // undefined
Bar.prototype // {constructor: ƒ}

函数对象从哪里来

Javascript世界所有对象都源自两个创世神,Object和Function,一个创建普通对象,一个创建函数对象,而Object本身就是一个构造函数,所以它也是被Function所创建。

通过前面的基础结构,我们可以简单推断出一个函数对象它的原型结构是什么样子

注意[[prototype]]并不是prototype这个公开的属性,它就是__proto__,前面已经详细解释过三个东西

function Bar(){}
Bar.__proto__ === Function.prototype // true

通过代码验证了,结构确实是这个结构,我们继续往上探索,Function.prototype的[[prototype]]是什么?Object创建普通对象,Function创建函数对象,Function.prototype是一个普通对象,自然是Object创建,?是什么呼之欲出,我们先用代码推断一下。

Function.prototype.__proto__ === Object.prototype // true
Object.__proto__ === Function.prototype // true

通过以上两行代码,我们终于把Function和Object联系起来了,也证明了Object确实是Function创建。

看到这里感觉是不是少了点什么?Function它也是一个函数对象,它的[[prototype]]呢?

根据上面的结构推断,只有可能是Function自己创建了自己,所以它的[[prototype]]指向了Function.prototype。

这里没有鸡生蛋,蛋生鸡的问题,这里的自己很明显是由native code创建了,也就是我们的JS引擎里面的原生代码,然后Function才执行自己的本身的功能。

到此,我们完成了Javacript世界之中原型链prototype chain的关系梳理。

下面我会放出一张非常经典流传十分之久的关系图,想不通的时候不妨看看最基本的那个结构,通过基本结构类比函数对象的结构,再把它们结合起来,就能变成下面这张图。

一些奇怪的代码

在Javascript之中我们有一个a instanceof b操作符,它的作用是判断b是否在a的原型链上面,它的原理就是

a.__ prot o__. … .__ proto __ .constructor === b

先小试牛刀

function Bar() {}
const Foo = new bar()
foo instanceof bar // true

结合上面所分析,再来看看以下代码,一切都说的通了

Object instanceof Function // ture
Object.__proto__.constructor === Function
Object instanceof Object // ture
Object.__proto__.__proto__.constructor === Object
Function instanceof Function // ture
Function.__proto__.constructor === Function
Function instanceof Object// ture
Function.__proto__.__proto__.constructor === Object

最后

整理了75个JS高频面试题,并给出了答案和解析,基本上可以保证你能应付面试官关于JS的提问。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

【前端基础】盘根错节的寄生世界之原型和原型链相关推荐

  1. 前端基础篇之CSS世界

    小刚老师 基本概念 盒模型四大金刚 好基友`line-height`和`vertical-align` 流的破坏 层叠规则 弹性布局 网格布局 文本控制 元素的显示与隐藏 基本概念 这些基本概念有些可 ...

  2. 前端基础进阶(七):函数与函数式编程

    纵观JavaScript中所有必须需要掌握的重点知识中,函数是我们在初学的时候最容易忽视的一个知识点.在学习的过程中,可能会有很多人.很多文章告诉你面向对象很重要,原型很重要,可是却很少有人告诉你,面 ...

  3. 前端面试知识点总结JavaScript基础之原型和原型链(二)

    一.JavaScript基础 原型和原型链 1.理解原型设计模式以及JavaScript中的原型规则 设计模式 1.工厂模式:在函数内建立一个对象,给对象赋予属性及方法再将对象返回设计模式. func ...

  4. 前端基础面试题大全-极乐科技(一)-JS部分

    2019独角兽企业重金招聘Python工程师标准>>> #JS部分 ###1.几种基本数据类型?复杂数据类型?值类型和引用数据类型?堆栈数据结构? 基本数据类型:Undefined. ...

  5. Web前端基础知识总结

    一.HTML和CSS 你做的页面在哪些流览器测试过?这些浏览器的内核分别是什么? IE: trident内核 Firefox:gecko内核 Safari:webkit内核 Opera:以前是pres ...

  6. 【前端面试题】前端基础 | 八股文 | HTTP网络 | Vue | React

    ⭐️ 本文首发自 前端修罗场(点击加入),是一个由 资深开发者 独立运行 的专业技术社区,我专注 Web 技术.Web3.区块链.答疑解惑.面试辅导以及职业发展.博主创作的 <前端面试复习笔记& ...

  7. 前端基础全面的面试题

    2019精选面试题.notehttps://blog.csdn.net/weixin_34099526/article/details/91461153 1.Vue实现数据双向绑定的原理是什么? 2. ...

  8. Web 前端基础知识面试大全

    目录 一.HTML 1.对 HTML 语义化的理解 2.区别:src 和 href 3.DOCTYPE 的作用 4.HTML5 的新特性 5.script 标签中的 defer 和 async 6. ...

  9. 前端基础知识点整理(html+css+js基础)、不包含框架

    css盒子模型 盒模型都是由四个部分组成的,分别是margin.border.padding和content. ​ 标准盒模型和IE盒模型的区别在于设置width和height时,所对应的范围不同.标 ...

最新文章

  1. 三、临时弹出一个QQ对话窗口
  2. python 内部函数,以及lambda,filter,map等内置函数
  3. 迷失在小镇上的日记(16)
  4. C++中private成员变量和protect成员变量的区别
  5. 解决Windows中PLSQL连接虚拟机中Oracle缓慢的问题
  6. Web开发小结 - 2
  7. 马云现身敦煌种梭梭树:蚂蚁森林即将突破1亿棵树
  8. dmp导入数据 oracle_oracle数据库:数据的导入导出及备份
  9. android 转码工具下载,视频格式转换工具app
  10. wifi分析仪android 9,Wifi分析仪(无线信号检测)
  11. 移动端中的vMin和vMax
  12. vuex的commit和dispatch
  13. 全球破解组织网址大全
  14. 微信小程序—刷脸实名认证
  15. 第十一届蓝桥杯 ——数字三角形
  16. 杭州随笔之欲把西湖比西子
  17. 为pr视频文件添加字幕
  18. 北京大学优秀计算机论文,计算机系在ESEC/FSE'20上发表的论文获得ACM SIGSOFT杰出论文奖...
  19. JNLP文件及JWS
  20. matlab 工业相机 曝光时间_工业相机的曝光、曝光时间、快门、增益

热门文章

  1. 怎么简单快速将CAD图纸转换成黑白的WMF格式?
  2. 前辈们的话--大疆技术总监的金玉良言
  3. 【阿不】深入ASP.NET数据绑定(下)—多样的绑定方式
  4. 2022-09-23 Drawable开发小技巧
  5. 使用jquery中$.each()方法来循环一个数据列表
  6. STM32F407+FreeRTOS+LWIP1.4.1: Error:..\FreeRTOS\portable\RVDS\ARM_CM4F\port.c,441
  7. 伊利安慕希酸奶产品正式在东南亚上市
  8. php mssql 字段名中文,php mssql中文乱码怎么办_后端开发
  9. 【最远点采样FPS】点云采样方式(一) — 最远点采样
  10. 简单一步解决SU速度慢、效率低问题