图解 Google V8
李兵
前盛大创新院高级研究员
26763 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 25 讲
图解 Google V8
15
15
1.0x
00:00/00:00
登录|注册

05|原型链:V8是如何实现对象继承的?

DogFactory.prototype和DogFactory.proto的关联
函数的proto属性
JavaScript的历史
使用new加构造函数创建对象
原型继承机制
new关键字的设计
JavaScript的历史
原型对象的关联
构造函数的隐藏属性
使用new关键字创建对象
使用构造函数创建对象
设置对象的原型
原型链
原型对象
对象的proto属性
思考题
总结
一段关于new的历史
构造函数怎么实现继承?
构造函数是怎么创建对象的?
实践:利用proto实现继承
基于原型的继承
JavaScript中的对象继承

该思维导图由 AI 生成,仅供参考

你好,我是李兵。
在前面两节中,我们分析了什么是 JavaScript 中的对象,以及 V8 内部是怎么存储对象的,本节我们继续深入学习对象,一起来聊聊 V8 是如何实现 JavaScript 中对象继承的。
简单地理解,继承就是一个对象可以访问另外一个对象中的属性和方法,比如我有一个 B 对象,该对象继承了 A 对象,那么 B 对象便可以直接访问 A 对象中的属性和方法,你可以参考下图:
什么是继承
观察上图,因为 B 继承了 A,那么 B 可以直接使用 A 中的 color 属性,就像这个属性是 B 自带的一样。
不同的语言实现继承的方式是不同的,其中最典型的两种方式是基于类的设计基于原型继承的设计
C++、Java、C# 这些语言都是基于经典的类继承的设计模式,这种模式最大的特点就是提供了非常复杂的规则,并提供了非常多的关键字,诸如 class、friend、protected、private、interface 等,通过组合使用这些关键字,就可以实现继承。
使用基于类的继承时,如果业务复杂,那么你需要创建大量的对象,然后需要维护非常复杂的继承关系,这会导致代码过度复杂和臃肿,另外引入了这么多关键字也给设计带来了更大的复杂度。
而 JavaScript 的继承方式和其他面向对象的继承方式有着很大差别,JavaScript 本身不提供一个 class 实现。虽然标准委员会在 ES2015/ES6 中引入了 class 关键字,但那只是语法糖,JavaScript 的继承依然和基于类的继承没有一点关系。所以当你看到 JavaScript 出现了 class 关键字时,不要以为 JavaScript 也是面向对象语言了。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

V8引擎在JavaScript中实现对象继承的方式是基于原型链的设计。与基于类的继承不同,JavaScript的继承机制通过每个对象都包含一个原型属性,指向原型对象,从而实现继承特性。通过原型链,对象可以访问其原型对象的属性和方法,形成了一种简洁而优美的继承方式。文章还介绍了利用`__proto__`属性实现继承的实践方法,以及通过构造函数创建对象的过程。通过`new`关键字配合函数,JavaScript虚拟机会返回一个对象,实现了对象的创建。整体而言,本文深入浅出地介绍了V8引擎是如何实现JavaScript中的对象继承,以及原型链的工作原理,为读者提供了清晰的技术概览。文章还回顾了JavaScript的历史,解释了为何JavaScript中使用了`new`关键字来创建对象,以及其与Java的关系。通过讲解构造函数实现继承的方式和`new`关键字的历史,读者可以更好地理解JavaScript中的继承机制。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《图解 Google V8》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(39)

  • 最新
  • 精选
  • 张青天
    DogFactory 是 Function 构造函数的一个实例,所以 DogFactory.__proto__ === Function.prototype DogFactory.prototype 是调用 Object 构造函数的一个实例,所以 DogFactory.prototype.__proto__ === Object.prototype 因此 DogFactory._proto_ 和 DogFactory.prototype 没有直接关系

    作者回复: 没问题

    2020-03-26
    6
    110
  • 搞学习
    推荐一篇挺好的文章,结合老师讲的一起看有奇效 https://juejin.im/post/5cc99fdfe51d453b440236c3

    编辑回复: 优秀

    2020-03-26
    27
  • sugar
    老师,这几节课看了有关对象,函数这些东西在v8的实现,感觉还不过瘾,想问下老师能否把文中提到的一些v8的实现思路,在文末增加一个链接直接跳转到v8的c++源代码里 具体到文件和行号?

    作者回复: 这个专栏定位还是给前端工程师的,所以根本没打算讲源码,源码比想象的复杂太多,光一个原型的实现就做了很多复杂的优化!比如通过隐藏类优化了很多原有的对象结构,所以通过直接修改—proto—会直接破坏现有已经优化的结构,造成严重的性能问题! 另外比如讲作用域的C++实现我觉得也没太大意义,有能力看代码的人结合文档和流程就可以直接去看代码了! 比如编译流程,代码的文档结构 在v8.dev中都有介绍.

    2020-03-26
    7
    10
  • 若川
    关于思考题,我以前写了一篇文章《面试官问:JS的继承》画了一张图可以很好的回答这个问题。 https://user-gold-cdn.xitu.io/2019/2/18/169014cf74620047?imageslim (极客时间评论不支持图片。只好放个图片链接了) 文章链接 https://juejin.im/post/5c433e216fb9a049c15f841b

    作者回复: 很赞

    2020-05-31
    8
  • mfist
    DogFactory.prototype 是Dog工厂函数实例对象的原型链(```dog = new DogFactory()```),dog实例上面没有属性或方法会去原型链上面寻找。 DogFactory.__proto__ 是函数对象的原型链 ,```function DogFactory(){} ``` 另外一种类似实现是 ```DogFactory = new Function([arg1, arg2] functionBody)``` 所以它应该指向Function.prototype。引用MDN一句话: Function对象继承自Function.prototype属性,它是不能被修改的。``` Function.prototype.toString() 得到 "function () { [native code] }"``` 所以两者是有本质区别的。要说有啥关联性的话,就是```DogFactory.prototype.constructor ===DogFactory // true``` DogFactory.prototype上面构造函数就是 DogFactory 今日总结 1. 普通对象上面有一个隐藏的__proto__对象,指向自己的原型。当在对象上面访问属性的时候会先在当前对象寻找,如果找不到再去原型链上面寻找。 2. javascript为了蹭到当时java的热度和迎合java程序员,起名为javascript,和模仿了 new Foo() 创建对象的语法(虽然和面向对象创建实例的底层逻辑完全不一样) ``` function Foo(){ this.name = 'foo' this.label = 'function' } const foo = new Foo() // new Foo执行的内部逻辑如下 let obj = {} obj.__proto__ = Foo.prototype let args = [...arguments] let result= Foo.call(obj, args) if (typeof result === 'object'){ return result } return obj ```

    作者回复: 赞

    2020-03-26
    8
  • tomision
    直接使用 __proto__ 属性,会有严重的性能问题。这个点可以详细说说嘛?

    作者回复: 隐藏类的优化措施优化过了对象,修改了proto的属性指向,相当于要重建整个隐藏类,必然会影响性能

    2020-03-26
    4
  • 伪装
    Null 设计的初衷是什么 它具体担任了什么样的角色

    作者回复: 最初NULL就代表是空,比如Number(null),就会返回一个0,可以把null看成是c中或者java中的null。 可以根据一个值是否是null,来判断做什么事情。 但是javascript同时支持原生类型和对象类型,null是一个对象,那么发明者认为,对象和原生类型进行默认转换,会造成很多误解,并且不容易发现错误,那么又设计了一个undefined,用来表示未使用的原始值,转换为数值时为NaN! 总的来说,这个设计糟糕的一塌糊涂,但是我们依然得使用它们 还需要一个类型来表示原生类型的

    2020-05-25
    3
  • 墨灵
    ``` const someFactory = (key) => { this.key = key } ``` 试问,someFactory能否成为一个构造函数? 答案是不能,箭头函数在js里也是一个比较特殊的存在,根本没是prototype的属性,自然也没有constructor

    作者回复: 赞

    2020-03-29
    3
  • 盖世英雄
    每个函数对象中都有一个公开的 prototype 属性,当你将这个函数作为构造函数来创建一个新的对象时, 这句话中: 都有一个 公开的 prototype属性,‘公开的‘ 是不是写错了? 上文还提到 prototype属性是隐藏的呢?还是我理解的不对呢?

    作者回复: —proto—是隐藏属性,prototype可是标准定义的

    2020-03-26
    3
  • 七月有风
    class 中的方法为什么要放在构造函数prototype上。而不是放在构造函数中?

    作者回复: 放在prototype属于全局的,只要继承了prototype的类都可以共同拥有该方法,放在构造函数中就属于当前对象了,具体放在什么地方要看具体需求了

    2020-04-08
    2
收起评论
显示
设置
留言
39
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部