prototype 属性和__proto__属性

大多数浏览器的 ES5 实现之中,每一个对象都有__proto__属性,指向对应的构造函数的prototype属性。ES6 Class 作为构造函数的语法糖,同时有prototype属性和__proto__属性,因此同时存在两条继承链。

(1)子类的__proto__属性,表示构造函数的继承,总是指向父类。

(2)子类prototype属性的__proto__属性,表示方法的继承,总是指向父类的prototype属性。

  1. class A {
  2. }
  3. class B extends A {
  4. }
  5. B.__proto__ === A // true
  6. B.prototype.__proto__ === A.prototype // true

上面代码中,子类B__proto__属性指向父类A,子类Bprototype属性的__proto__属性指向父类Aprototype属性。

这样的结果是因为,类的继承是按照下面的模式实现的。

  1. class A {
  2. }
  3. class B {
  4. }
  5. // B 的实例继承 A 的实例
  6. Object.setPrototypeOf(B.prototype, A.prototype);
  7. // B 的实例继承 A 的静态属性
  8. Object.setPrototypeOf(B, A);
  9. const b = new B();

《对象的扩展》一章给出过Object.setPrototypeOf方法的实现。

  1. Object.setPrototypeOf = function (obj, proto) {
  2. obj.__proto__ = proto;
  3. return obj;
  4. }

因此,就得到了上面的结果。

  1. Object.setPrototypeOf(B.prototype, A.prototype);
  2. // 等同于
  3. B.prototype.__proto__ = A.prototype;
  4. Object.setPrototypeOf(B, A);
  5. // 等同于
  6. B.__proto__ = A;

这两条继承链,可以这样理解:作为一个对象,子类(B)的原型(__proto__属性)是父类(A);作为一个构造函数,子类(B)的原型对象(prototype属性)是父类的原型对象(prototype属性)的实例。

  1. Object.create(A.prototype);
  2. // 等同于
  3. B.prototype.__proto__ = A.prototype;

extends 的继承目标

extends关键字后面可以跟多种类型的值。

  1. class B extends A {
  2. }

上面代码的A,只要是一个有prototype属性的函数,就能被B继承。由于函数都有prototype属性(除了Function.prototype函数),因此A可以是任意函数。

下面,讨论三种特殊情况。

第一种特殊情况,子类继承Object类。

  1. class A extends Object {
  2. }
  3. A.__proto__ === Object // true
  4. A.prototype.__proto__ === Object.prototype // true

这种情况下,A其实就是构造函数Object的复制,A的实例就是Object的实例。

第二种特殊情况,不存在任何继承。

  1. class A {
  2. }
  3. A.__proto__ === Function.prototype // true
  4. A.prototype.__proto__ === Object.prototype // true

这种情况下,A作为一个基类(即不存在任何继承),就是一个普通函数,所以直接继承Function.prototype。但是,A调用后返回一个空对象(即Object实例),所以A.prototype.__proto__指向构造函数(Object)的prototype属性。

第三种特殊情况,子类继承null

  1. class A extends null {
  2. }
  3. A.__proto__ === Function.prototype // true
  4. A.prototype.__proto__ === undefined // true

这种情况与第二种情况非常像。A也是一个普通函数,所以直接继承Function.prototype。但是,A调用后返回的对象不继承任何方法,所以它的__proto__指向Function.prototype,即实质上执行了下面的代码。

  1. class C extends null {
  2. constructor() { return Object.create(null); }
  3. }

实例的 __proto__ 属性

子类实例的__proto__属性的__proto__属性,指向父类实例的__proto__属性。也就是说,子类的原型的原型,是父类的原型。

  1. var p1 = new Point(2, 3);
  2. var p2 = new ColorPoint(2, 3, 'red');
  3. p2.__proto__ === p1.__proto__ // false
  4. p2.__proto__.__proto__ === p1.__proto__ // true

上面代码中,ColorPoint继承了Point,导致前者原型的原型是后者的原型。

因此,通过子类实例的__proto__.__proto__属性,可以修改父类实例的行为。

  1. p2.__proto__.__proto__.printName = function () {
  2. console.log('Ha');
  3. };
  4. p1.printName() // "Ha"

上面代码在ColorPoint的实例p2上向Point类添加方法,结果影响到了Point的实例p1

es6 prototype 属性和__proto__属性相关推荐

  1. JS中函数的prototype属性和对象的__proto__属性

    <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8" ...

  2. JS中关于构造函数、原型链、prototype、constructor、instanceof、__proto__属性

    在Javascript不存在类(Class)的概念,javascript中不是基于类的,而是通过构造函数(constructor)和原型链(prototype chains)实现的.但是在ES6中引入 ...

  3. es6 __proto__属性,Object.setPrototypeOf(),Object.getPrototypeOf()

    __proto__属性,Object.setPrototypeOf(),Object.getPrototypeOf() JavaScript 语言的对象继承是通过原型链实现的.ES6 提供了更多原型对 ...

  4. javascript中的prototype原型、_proto_属性、原型链

    prototype原型 JavaScript是面向对象的语言,那么继承自然是其重要特征之一.与标准面向对象语言不同,JavaScript继承主要通过prototype原型实现.每一个函数都具有prot ...

  5. ES6之符号与符号属性

    引 在 JS 已有的基本类型(字符串.数值.布尔类型. null 与 undefined )之外, ES6 引入了一种新的基本类型:符号(Symbol).符号起初被设计用于创建对象私有成员,而这也是 ...

  6. javascript 原型属性(prototype 属性)与 实例属性(自身属性)

    讲到原型属性,prototype属性,实例属性,自身属性,首先我们要明白这四者之间的关系.我查了一些资料,原型属性又叫prototype属性,实例属性又叫自身属性.只是叫法不同.下面我要引用他人写的一 ...

  7. es6 Class 的 new.target 属性

    Class 的 new.target 属性 new是从构造函数生成实例对象的命令.ES6 为new命令引入了一个new.target属性,该属性一般用在构造函数之中,返回new命令作用于的那个构造函数 ...

  8. JS中的可枚举属性与不可枚举属性的学习以及扩展

    最近在学习对象遍历的方法时总是能看到的两个词,一个是"原型",一个是"枚举属性".一开始感觉自己大概明白"枚举属性"的意思,但是叫我解释却又 ...

  9. Reflect.ownKeys()与Object.keys()区别 以及 JS中的可枚举属性与不可枚举属性

    代码test1: var obj = {} Object.defineProperty(obj, 'method1', {value: function () {alert("Non enu ...

最新文章

  1. plt.figure(figsize(x,y))设置后后续程序都跟着改变,如何处理?走破解它!
  2. 设计模式-简单工厂模式
  3. DL之CNN:卷积神经网络算法简介之原理简介——CNN网络的3D可视化(LeNet-5为例可视化)
  4. 计算机动画的主要应用领域,简述计算机的主要特点和主要应用领域
  5. linux之ps命令
  6. canvasnest 移动距离_GitHub - XiaoxinJiang/canvas-nest: 仿知乎登录页面canvas-nest
  7. [渝粤教育] 西南科技大学 电气CAD 在线考试复习资料
  8. linux命令行中的大括号,linux命令行学习(19):花括号扩展(brace expansion)
  9. mac 安装 brew 镜像
  10. windows快捷键大全
  11. ubuntu14.04不能上网
  12. LINUX(CENTOS7.X)SVN部署文档+pycharmSvn
  13. 10行Python代码实现抽奖助手自动参与抽奖
  14. 日本人的姓及一些姓氏的读法(转)
  15. X86:2:X86处理器架构
  16. 香港服务器托管服务怎么样?
  17. 随记1 MySQL之特殊字符(表情)的存储以及读取乱码问题
  18. 【内网安全】——windows信息收集
  19. 佟年计算机天才不会打游戏,亲爱的热爱的:Gun神带佟年开黑,网友:甜蜜游戏时间...
  20. MIT-BIH心电数据库的使用

热门文章

  1. 使用performance monitor 查看 每一个cpu core的cpu time
  2. Hibernate 原汁原味的四种抓取策略(转)
  3. HTML5应用程序缓存Application Cache
  4. ASP.NET Core和Angular 2双剑合璧
  5. 技术人生:给自己安慰的10句温馨话
  6. AD数据库的备份与还原
  7. 在Struts2中实现文件上传(二)
  8. pytorch学习笔记(5):vgg实现以及一些tricks
  9. 怎么去观察php运行原理,php运行原理如何理解,具体看代码?
  10. pytorch1.0 用torch script导出模型