定义ES6类方法的差异

作者: 打铁大师 | 来源:发表于2018-02-20 14:37 被阅读0次

原文请戳这里Differences in Defining ES6 Class Methods

在ES6中,有两种普遍的方式用来定义class methods,但他们的行为完全不同。

第一种方式是将class methods定义为标准的类函数。

注意:这种方式,方法定义在类的原型

class A {
    foo() {  
      console.log('foo from A')
    }
  }

但是你也可以把它们定义为实例的具体函数

注意:这种定义方式不是ES6标准语法,但被transform-class-properties支持,因此广为流行。

注意:这种定义方式,方法其实是定义在构造函数内的,即直接定义在实例上的,而不是构造函数的原型上。

class A {
    foo = () => {
        console.log('foo from A')
    }
}

如果你知道ES6的箭头函数那么第一个区别很明显:它将函数调用的this变量绑定到了函数定义范围中的this变量。因此使用第二种方式定义,this被绑定到了当前的类的实例对象上。

我们可以不使用箭头函数,使用标准的class method也能实现相同的功能,只是需要在构造函数内进行额外的绑定。

class A { 
    constructor() {
      this.foo = this.foo.bind(this)
    }

    foo() {
        console.log('foo from A')
    }
}

您现在可能会认为以下类定义具有相同的行为:


0_3jvz23ydPSbkA2r5.png

然而,当我们使用javascript的类继承的时候,两者的行为完全不同。

类继承产生的不同结果:

让我们运行下面的代码:

class A { 
  constructor() {
      this.foo = this.foo.bind(this)
  }

  foo() {
      console.log('foo from A')
  }
}

class B extends A {
    foo() {
      super.foo();
      console.log('foo from B')
    }
}
new B().foo()

预期结果如下:

foo from A
foo from B

现在我们尝试使用箭头函数:

class A { 
    foo = () => {
      console.log('foo from A')
    }
}

class B extends A {
    foo = () => {
        super.foo();
        console.log('foo from B')
    }
}
new B().foo()

我们得到错误:

Cannot read property 'call' of undefined
0_EIbiqVDV59cHNOSg.png

这里发生了什么?

无论何时JavaScript中,当你调用了super.someFunction时,都会在__.proto__中查找someFunction关键词——这就是JavaScript类继承的实现方式。之所以我们在这得到了一个错误,
是因为foo不在new B()实例对象的__proto__上。

这告诉我们,不能在子类中使用箭头函数。箭头函数总是只能通过类实例属性来定义。那么,我们的classtransform-class-properties实际上都做了些什么:当具体的class instance被创建时,首先会在构造函数内附加函数。

 //第二种方式定义方法的本质是在构造函数内附加一个箭头函数,因此this会自动绑定了实例对象。
class A {
    constructor() {
          this.foo = () => {
          console.log('foo from A')
        }
     }
}  

当然,这样做,foo不会出现在__proto__且使得foo在扩展的对象中不可用。如果你需要一个方法在派生类中可以被调用(同时你希望使用ES6的class语法),可以使用class method的简写形式定义。

class A { 
  constructor() {
      this.foo = this.foo.bind(this)
  }

  foo() {
      console.log('foo from A')
  }
}

class B extends A {
    foo() {
         super.foo();
        console.log('foo from B')
    }
}
new B().foo()

最初发表于 cmichel.io

相关文章

  • 定义ES6类方法的差异

    原文请戳这里Differences in Defining ES6 Class Methods 在ES6中,有两种...

  • 深入es6之class

    es5定义一个类 es6定义一个类 es6原型方法(内部this是实例化的类) 静态方法(内部this是类) 继承

  • javascript中ES6的class写法

    在ES6中,javascript实现类定义、类继承及类中定义变量,构造方法,一般方法,静态方法 代码中均有注释

  • ES6 class与继承

    class是什么 class是定义类的方法。ES6之前用构造函数的方式定义类,ES6引入了class。 class...

  • JavaScript ES6 类的静态方法、属性和实例方法、属性

    类相当于实例的原型,ES6类的声明中可以定义实例方法、实例属性和静态方法。 ES6 明确规定, Class 内部只...

  • JavaScript入门——类(五)

    类定义(ES6) ES6 的类只是基于原型的语法糖;更易用。类支持基于原型的继承、调用父类、实例和静态方法,构造器...

  • ES6:class static

    es6 的 static 定义的是类的方法只有类能调用,而普通方法是实例的方法只有类实例能调用。变量也一样。

  • JavaScript-13 ES6和对象

    ES6类和对象 在ES6之前如果定义一个类? 通过构造函数来定义一个类 在ES6之前定义类就是构造函数,静态属性和...

  • ES6 class

    ES6 class 基本概念 类的方法都定义在原型上 类的方法是不可枚举的 类必须使用 new 来调用(typeo...

  • 【ES6】class的基本使用与继承

    生成实例对象的传统方法是通过构造函数 定义类 ES6 引入了class(类),让javascript的面向对象编程...

网友评论

    本文标题:定义ES6类方法的差异

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