由于写本文时全部是在编辑器中边写代码边写感想的,所以,全部思想都写在代码注释里面了
// 类继承 //todo.1 extends 关键字 class Animal { constructor(name) { this.speed = 0; this.name = name; } run(speed) { this.speed = speed; console.log(`${this.name} runs with speed ${this.speed}`); } } // 如果“派生类”使用constructor函数,则必须在constructor调用this之前使用super来调用被继承类的constructor // 如果“派生类”没有使用constructor函数,则默认会生成一个constructor,代码如下 /** * constructor(...args) { * super(...args) * } */ // 为什么需要super() ? // 因为“派生类(derived constructor)的构造函数与其他函数之间的区别在于其具有特殊的内部属性[[ConstructorKind]]:derived” // 这个属性会影响new 的行为; 当通过new执行一个常规函数时,它将创建一个空对象,并将这个空对象赋值给this; // 但是当继承的constructor执行时,它不会执行此操作,它期望父类的constructor来完成这项工作。因此派生类必须执行super才能执行 // 父类的constructor来完成这项工作,否则this指向的那个对象不会创建,并且程序会报错! class Rabbit extends Animal { constructor(name, color) { super(name); this.color = color; } } const rabbit = new Rabbit("兔子", "白色"); //todo.2 深入探究内部原理和[[HomeObject]] // 让我们先来看一个例子。 const animal = { name:'Animal', eat() { console.log('animal'); } } const tiger = { __proto__:animal, name:'tiger', eat() { this.__proto__.eat.call(this); } } const youngTiger = { __proto__:tiger, name:'youngTiger', eat() { this.__proto__.eat.call(this); } } tiger.eat(); // animal // youngTiger.eat(); // RangeError: Maximum call stack size exceeded // 为什么会报错?让我们来深入探究一下 /** * 在youngerTiger.eat中 * this.__proto__.eat.call(this) * 等于 * youngTiger.__proto__.eat.call(this) * 等于 * tiger.eat.call(this) * 在tiger.eat中 * this.__proto__.eat.call(this) * 等于 * youngTiger.__proto__.eat.call(this) * 等于 * tiger.eat.call(this) */ // 解决方案:[[HomeObject]] // 当一个函数被定义为类或者对象方法时,它的 [[HomeObject]] 属性就成为了该对象。 // 然后 super 使用它来解析(resolve)父原型及其方法。 let plant = { name:'Plant', grow() { console.log(`${this.name} growing`); } } let flower = { __proto__:plant, grow() { super.grow(); } } let greenFlower = { __proto__:flower, grow() { super.grow() } } greenFlower.grow();//Plant growing // [[HomeObject]]内置属性是被绑定到JavaScript对象上的,“方法”由哪个对象创建,则 // [[HomeObject]]指向哪个对象,并且[[HomeObject]]一旦创建就是不可变的 // 而且只能被super解析。注意:“方法”不是“函数属性”, // “方法” {method(){}},“函数属性”{method:function(){}} // 解析,当对象嵌套继承时,为了避免Maximum call stack size exceeded错误, // 我们可以使用super来代替 this.__proto__.method.call(this)方法,前提是 // [[HomeObject]]属性存在,并且__proto__存在