美文网首页
super [[HomeObject]]

super [[HomeObject]]

作者: Time_Notes | 来源:发表于2020-05-23 06:20 被阅读0次

super既可以当做函数使用,也可以当做对象使用,两种使用的时候完全不一样。

函数用时: 使用super(...)调用父构造函数(仅在constructor函数中)

在constructor中必须调用super方法,因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工,super就代表了父类的构造函数

super虽然代表了父类A的构造函数,但是返回的是子类B的实例,即super内部的this指的是B,因此 super()在这里相当于A.prototype.constructor.call(this, props)

在super()执行时,它指向的是子类B的构造函数,而不是父类A的构造函数。也就是说,super()内部的 this指向的是B。

当做对象使用: 在普通方法中指向父类的原型对象,使用super.method(...)调用父方法;在静态方法中指向父类。

在子类的方法中super.print();指向的是父类原型上的方法。

因为super的两种用法,所以es6规定必须要明确使用方式,像console.log(super)就会报错。


当一个对象方法运行时,它将当前对象作为this。如果调用super.method()那么如何检索method?容易想到,需要从当前对象的原型中取出method。

也许可以从this的[[Prototype]]中获得方法,就像this .__ proto __.method一样?不幸的是,这是行不通的。

这里,rabbit.eat()调用父对象的animal.eat()方法:

let animal = {

  name: "Animal",

  eat() {

    alert(`${this.name} eats.`);

  }

};

let rabbit = {

  __proto__: animal,

  name: "Rabbit",

  eat() {

    // that's how super.eat() could presumably work

    this.__proto__.eat.call(this); // (*)

  }

};

rabbit.eat(); // Rabbit eats.

在(*)这一行,从原型animal中取出eat,并以当前对象的上下文中调用它。注意.call(this)在这里很重要,因为只写this .__ proto __.eat()的话,eat的调用对象将会是animal,而不是当前对象。以上代码的alert是正确的。

但是再添加一个对象到原型链中,就要出事了:

let animal = {

  name: "Animal",

  eat() {

    alert(`${this.name} eats.`);

  }

};

let rabbit = {

  __proto__: animal,

  eat() {

    // ...bounce around rabbit-style and call parent (animal) method

    this.__proto__.eat.call(this); // (*)

  }

};

let longEar = {

  __proto__: rabbit,

  eat() {

    // ...do something with long ears and call parent (rabbit) method

    this.__proto__.eat.call(this); // (**)

  }

};

longEar.eat(); // Error: Maximum call stack size exceeded

这原因一眼可能看不透,但如果跟踪longEar.eat()调用,大概就知道为什么了。

在(*)和(**)两行中, this的值是当前对象(longEar)。重点来了:所有方法都将当前对象作为this,而不是原型或其他东西。

因此在两行(*)和(**)中this.__ proto__的值都是rabbit,他们都调用了rabbit.eat,于是就这么无限循环下去。情况如图:

1.在longEar.eat() 里面,(**)行中调用了rabbit.eat,并且this=longEar。

// inside longEar.eat() we have this = longEar

this.__proto__.eat.call(this) // (**)

// becomes

longEar.__proto__.eat.call(this)

// that is

rabbit.eat.call(this);

2.然后在rabbit.eat的(*)行中希望传到原型链的下一层,但是this=longEar,所以this.__proto__.eat又是rabbit.eat!

// inside rabbit.eat() we also have this = longEar

this.__proto__.eat.call(this) // (*)

// becomes

longEar.__proto__.eat.call(this)

// or (again)

rabbit.eat.call(this);

因此rabbit.eat在无尽循环调动,无法进入下一层。这个问题不能简单使用this解决。


为了提供解决方案,JavaScript为函数添加了一个特殊的内部属性:[[HomeObject]]

[[HomeObject]]:当函数被指定为类或对象方法时,其[[HomeObject]]属性为该对象。

这实际上违反了unbind函数的思想,因为方法记住了它们的对象,并且[[HomeObject]]不能被改变,所以这是永久bind(绑定)。

在JavaScript这是一个很大的变化,但是这种改变是安全的,[[HomeObject]]仅用于在super中获取下一层原型,所以它不会破坏兼容性。

来看看它是如何在super中运作的:

let animal = {

  name: "Animal",

  eat() {        // [[HomeObject]] == animal

    alert(`${this.name} eats.`);

  }

};

let rabbit = {

  __proto__: animal,

  name: "Rabbit",

  eat() {        // [[HomeObject]] == rabbit

    super.eat();

  }

};

let longEar = {

  __proto__: rabbit,

  name: "Long Ear",

  eat() {        // [[HomeObject]] == longEar

    super.eat();

  }

};

longEar.eat();  // Long Ear eats.

每个方法都会在内部[[HomeObject]]属性中记住它的对象,然后super使用它来解析原型。

在类和普通对象中定义的方法中都定义了[[HomeObject]],必须使用method()而不是"method: function()"。使用非方法语法(non-method syntax)没有设置[[HomeObject]]属性,继承也不起作用

let animal = {

  eat: function() { // should be the short syntax: eat() {...}

    // ...

  }

};

let rabbit = {

  __proto__: animal,

  eat: function() {

    super.eat();

  }

};

rabbit.eat();  // Error calling super (because there's no [[HomeObject]])

相关文章

  • super [[HomeObject]]

    super既可以当做函数使用,也可以当做对象使用,两种使用的时候完全不一样。 函数用时:使用super(...)调...

  • Super, super, super, super happy

    Parent diaries for 137th days weather:sunny Wed...

  • Super, super, super, super fun d

    亲子日记第136天 天气:晴 星期二 今天是周二,超级超级超级超级超级超级开心的一天٩(๑^o...

  • Class中的super简析

    super当作函数使用 super()执行父类的构造函数 super() 返回的是子类的实例,即 super 内部...

  • reactES6写法

    注意: super()是为了使用this,必须在使用this之前声明super(); super(props)这个...

  • JAVA面试题

    Q:super()与 this()的区别? A:This():当前类的对象,super 父类对象。 Super()...

  • iOS - super | super | super clas

    super 是编译器的指示符,不是指针,只是一个标识符,代表调用父类的方法,调用者还是自己本身 superclas...

  • super

    super关键字的使用 super理解为:父类的 super可以用来调用:属性、方法、构造器 super的使用:(...

  • Java 泛型 <? super T> 中 supe

    Java 泛型 中 super 怎么 理解?与 extends 有何不同? super只能...

  • Wildcards with super

    What is Wildcards with super The quizzical phrase ? super...

网友评论

      本文标题:super [[HomeObject]]

      本文链接:https://www.haomeiwen.com/subject/sejiuhtx.html