react开发中类的继承关系

最近开发中碰到一个特殊需求,需要处理类的继承关系。按我预期的方式进行处理,本来一切运行正常,但有一处代码无论如何都是在我预期外的,导致运行出错。本着折腾的精神,遂研究之~

首先说一下JavaScript中类的情况,所有对象都是Object的实例,所以包含以下关系(object是Object的实例):

  • object.__proto__ = Object.prototype
  • object.__proto__.constructor = Object

只要满足这种关系,即可证明这是类与实例的关系,instanceof也是基于这个原理查找原型链的。

如果此时有类Foo、Bar,Foo是基类,Bar继承Foo,代码如下:

class Foo { }
Class Bar extends { }

此时得到以下关系:

  • Foo.prototype.constructor = Foo
  • Foo.prototype.__proto__ = Object.prototype
  • Foo.__proto__ = Function.prototype
  • Foo.__proto__.constructor = Function
  • Foo.__proto__.__proto__= Object

由此可见,Foo是Function的实例,并且继承Object

然后说一下基本的情况,有一个类Bar,继承类Foo,Foo是从第三方库导入的,代码如下:

import Foo from 'foo'
class Bar extends Foo { }
class Baz extends Bar { }

此时得到以下关系:

  • Bar.prototype.constructor = Bar
  • Bar.prototype.__proto__ = Foo.prototype
  • Bar.__proto__ = Foo
  • Baz.prototype.constructor = Baz
  • Baz.prototype.__proto__ = Bar.prototype
  • Baz.__proto__ = Bar

这里有一处比较特殊,就是Bar虽然也是Function的实例,但在底层表现上和Foo有差别。Foo连接的是Function的实例,Bar是直接连接Foo本身。

然而,在react项目的开发中,碰到一个奇怪的问题,类组件的继承,对应底层关系和预期不一样。重新思考了JavaScript中prototype/__proto__/constructor的关系,并且反复测试后,得出以下关系(Foo/Bar/Baz均为react组件,其中Foo为外部组件):

  • Bar.prototype.constructor = Bar
  • Bar.prototype.__proto__ = Foo.prototype
  • Bar.__proto__ = Foo
  • Baz.prototype.constructor = Baz
  • Baz.prototype.__proto__ = Bar.prototype
  • Baz.__proto__ = A
  • Baz.__proto__.prototype = B
  • Baz.__proto__.prototype.constructor = C
  • Baz.__proto__.prototype.__proto__ = Bar.prototype
  • Baz.__proto__.__proto__ = Bar

由关系可以得知,Bar直接继承外部类Foo时,从底层看与非react组件没有区别。如果是类组件嵌套继承,非直接继承外部类的Baz情况就变得复杂了,甚至A/B/C三处的情况不明确,怀疑是webpack打包的时候中间还多了一层。

按照这个原理,把处理继承关系的代码调整一下,终于一切正常了。

此条目发表在原创空间, 技术随笔分类目录。将固定链接加入收藏夹。

发表评论