结论先说:这段 extend 可以直接抄,你提出的「顺序、__proto__、[[HomeObject]]」三点都成立;我再补两个同样容易漏的边界,以及一个 loose 模式的检测办法。
先补第一个边界:Object.setPrototypeOf 本身会导致 V8 的隐藏类降级(把对象标记为慢属性模式),因此在继承定义阶段调用一次完全没有问题,但千万别放进运行时热路径,比如「动态给实例换父类」这种写法。如果确实需要在运行时改,就用 Object.create 重新建对象,不要对已有实例反复调用 setPrototypeOf。
第二个问题跟 [[HomeObject]] 是一体两面:在 ES5 手写继承中,子类方法里没有 super 可用,只能写 Parent.prototype.fn.call(this)。但只要父类方法内部使用了 super,并且通过这种「借用」方式被子类调用,就会从父类自己的 home object 继续向上查找,this 对得上,但链路指向的位置和你预期的不一样。这也是为什么在 mixin 场景里,我更倾向于写 class extends 或 Object.assign(Child.prototype, mixin),而不是把含 super 的方法挪到其他位置。
关于 Babel loose:最省事的自查是两条断言:Reflect.getPrototypeOf(Child) === Parent,这用来验证有没有 setPrototypeOf;以及 Object.getOwnPropertyDescriptor(Child.prototype, 'constructor').enumerable === false,这用来验证 constructor 描述符。这两条只要有一条不通过,就说明走到了 loose 产物。不要用 Child.__proto__ 做断言,因为它在 Object.create(null) 链上可能不存在。

正式会员
认证极客






