基础

class是一个语法糖,只是在写法上更清晰简洁。可以看做是构造函数的另一种写法:

class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    
    sayName() {
        alert(this.name);
    }
}

var person1 = new Person("Angela", 18);
person1.sayName();  // Angela

以上构造了Person类,其中constructor函数作为构造函数,定义实例属性,sayName是定义在原型的方法。创建新的实例需要使用new命令。

类的内部定义的所有方法都是不可枚举的;类的属性名可以使用表达式;

类和模块的内部,都默认使用严格模式。类的声明不会提升;必须保证实例对象在声明类之后创建。

constructor方法

定义类的构造函数,使用new创建实例时自动调用该方法,如果未定义则会自动创建一个空构造函数;

默认返回实例对象(this),但如果在构造函数中指定返回另一个类的实例,则创建的实例对象属于指定的类;

      class Fruit {
        constructor() {
          return new Person("Apple", 2);
        }
      }
      var apple = new Fruit();
      console.log(apple instanceof Fruit);  // false
      console.log(apple instanceof Person); // true

实例对象

类的实例对象共享同一个原型,除非显示定义在实例对象的属性,其他都是定义在原型上。

实例对象有一个__proto__属性指向原型,但如果要获取原型建议使用Object.getPrototypeOf;

Class表达式

用类似于函数表达式的另一种写法:

      const Book = class {
        constructor(name, price) {
          this.name = name;
          this.price = price;
        }
        sell() {
          console.log(this.name+": $"+this.price);
        }
      }
      var book1 = new Book("English", 10);
      book1.sell(); // English: $10

类名为等号前的变量名,如果等号后的class之后跟一个名称则只能在类内部使用,指代类本身。

私有方法和私有属性

把私有属性和方法名设置为Symbol值,可以达到私有化的效果;

目前有提案建议把属性和方法名前加“#”前缀使其私有化。

this的指向

在类中this默认指向当前实例对象,但如果单独在类之外使用则会指向方法运行时的环境对象;

可以在构造函数中绑定this,或使用箭头函数,或使用Proxy;

name属性

类的name属性返回类名;

Class的静态方法

类相当于实例的原型,所有在类中定义的方法都会被实例继承,如果在一个方法前加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,称为“静态方法”。

静态方法中的this指向类而不是实例对象。

Class的静态属性和实例属性

Class内部只有静态方法,没有静态属性,可以通过Class.propName为Class指定静态属性。

新的提案中,类中实例属性可以直接在Class内部使用等号列出而不必一定要在构造函数中指定;类的静态属性可以在属性名前加static

new.target属性

new.target一般用在构造函数中,如果使用new命令调用构造函数,该属性为该构造函数的类名,否则为undefined

当子类继承父类时,这个属性返回子类;

类的继承

      class Ebook extends Book {

      }
      var book2 = new Ebook("World", 5);
      book2.sell(); // world, $5
      console.log(book2 instanceof Book); // true
      console.log(book2 instanceof Ebook); // true
      console.log(book2); // Ebook {name:'world', price:5}

在子类的构造函数中需要使用super获得父类,才能正确获得this

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

      class Ebook1 extends Book {
        constructor(name, price) {
          super(name, price);
          this.type = "e-book";
        }
        read() {
          console.log("let\'s read this new "+this.type+"--"+this.name);
        }
      }
      var book3 = new Ebook1("Campus Chinese", 15);
      book3.read(); // let's read this new e-book--Campus Chinese
      console.log(book3); // Ebook1 {name: "Campus Chinese", price: 15, type: "e-book"}

如果是以下写法会报错

      class Ebook1 extends Book {
        constructor() {
          this.type = "e-book";  
        }
        read() {
          console.log("let\'s read this new "+this.type+"--"+this.name);
        }
      }
      var book3 = new Ebook1("Campus Chinese", 15);
          /*Uncaught ReferenceError: Must call super constructor in derived class 
          *before accessing 'this' or returning from derived constructor
          */

而如果没有指定constructor方法则会默认添加:

      class Ebook1 extends Book {
      // 未显式指定则默认添加
        constructor(...args) {
           super(...args);
        }
      }

父类的静态方法也会被子类继承;

super的应用除了作为函数,在子类构造函数中指代父类的构造方法并有指向子类的this,还可以作为对象应用于普通方法中,指向该函数的父类的原型,而用在静态方法中,则指向方法的父类;

使用super时必须显示指定是作为对象还是作为函数使用;

extends 也可以用来继承原生构造函数。

      class myArray extends Array {
        constructor() {
          super();
        }
      }
      var arr1 = new myArray();
      arr1.push("4");
      arr1.push("8");
      var arr2 = arr1.map((x) => x / 2);
      console.log(arr1, arr2); // myArray(2) ["4", "8"]  myArray(2) [2, 4]

 posted on 2018-06-18 21:25  木汀  阅读(144)  评论(0编辑  收藏  举报