关于ES6中继承的问题 B继承A B.__proto__ = A?
先附上代码
class A{}
class B extends A{}
B.__proto__ === A //true
B.__proto__ === Function.prototype //false
typeof B //function
B.constructor === Function //true
我们知道,每个实例对象( object )都有一个私有属性(称之为 __proto__
)指向它的构造函数的原型对象(prototype )
class
是语法糖,本质上还是个函数,因此B
实际上是个函数,可以看作通过new Function
创建出来的Function
对象实例
那么问题来了B.__proto__
不应该等于Function.prototype
吗?为什么等于A
呢?这是特殊规定的吗?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
所以
B.__proto__ === A
ES6 标准入门里是这么写的
考虑下述代码
你可以发现,子类 B 继承了父类的
sayHi
静态方法,当然,这是规范的规定的,题主的困惑是由于不了解这一规定导致的。而具体到规范的实现,在 sec-runtime-semantics-classdefinitionevaluation,主要的逻辑在
仿照规范,类似的代码,可能就是这样
为了和规范保持一致,我的变量名基本都是用规范里的名称,有空的话,可以读读规范。
B.__proto__.__proto__ 确实是
Function.prototype
,但首先它的原型是 A ,其原型的原型才是函数原型。因为定义在 A 上的静态方法 B 也要继承。更新:
每一个对象都有原型,但是对象的原型并不一定是对象的构造函数的 prototype 属性。
我在这里先声明一下几个术语,前端届对原型的称呼一直比较混乱:
原型:
点操作符
或者[ ]
访问属性时,会先检查对象本身的属性,如果不存在则会检查对象的原型,如果还不存在则会继续检查对象原型的原型直到原型的尽头 Object.prototype ,它没有原型,它的原型是 null,这个就是所谓的原型链。new 一个构造函数发生了什么:
什么是继承?
基于 prototype 的继承模拟基于 class 的继承:
说的有点多,回到你的问题:
每一个对象都有原型,但是对象的原型并不一定是对象的构造函数的 prototype 属性。
且不说 constructor 属性并不是一个锁死的属性,JS 中的有些对象也并不一定存在一个构造器。
如上代码展示,其实 JS 中对象的构造器不是在所有场合都合理且有意义。构造函数这个概念在基于 prototype 继承的体系里其实是不需要的,它是 JS 模拟基于类的继承加入的东西。
那么题主的问题到底出现在哪里呢?出现在这里:
class
是语法糖,本质上还是个函数,因此B
实际上是个函数,可以看作通过new Function
创建出来的Function
对象实例class 是语法糖没错,本质是函数也没错,错在 class B 并不能看作是 new Function 构造出来的,class A 可以,但是 B 不行。因为 B extends A,B 是通过 A 构造出来的。你忘了,JS 继承的本质是对象继承。 class B extends A 这里隐含了两个 prototype 继承。 B.prototype 继承了 A.prototype, 同时 B 继承了 A。
因为静态属性也是需要继承的,所以 B 并不是直接通过 new Function 构造出来的,B 是通过 A 作为原型构造出来的,即 B = Object.create(A); 这样 B 才能获得 A 上定义的静态属性和方法,才符合基于 class 的继承的表现。
所以,B.constructor 在这里并没有很符合实际的意义,并不存在一个函数它把 B 构造了出来。从原型的角度看待就不存在这种问题,B 用了 A 当原型,A 用了 Function.prototype 当原型,仅此而已。