es6

es6-类的用法

""

绯雨闲丸 发布于

“”

类class是es6引入的最重要特性之一。在没有class之前,我们只能通过原型链来模拟类。

类(class)

如果你用过java这样的纯面向对象语言,那么你会对class的语法非常熟悉。

class People {
    constructor(name) { //构造函数
          this.name = name;
    }
    sayName() {
          console.log(this.name);
    }
}

上面定义了一个People类,他有一个属性 name 和一个方法 sayName(),还有一个构造函数; 你可以这样使用这个类:

var p = new People("Tom");
p.sayName();

就像函数有函数声明和函数表达式两种定义方式,类也可以通过类表达式来定义:

let People = class {
    constructor(name) { //构造函数
          this.name = name;
    }
    sayName() {
          console.log(this.name);
    }
  }

你可能以为类声明和类表达式的区别在于变量提升的不同。但是事实是无论是类声明还是类表达式的方式来定义,都不会有变量提升。所以下面的写法是错的:

var p = new People("Tom");    //错误,People 未定义
class People {
    //...
};

类中的所有方法默认都是严格模式 strict mode,所以不用再次声明了。

继承(extends)

通过关键字 extends 来继承一个类,并且,可以通过 super 关键字来引用父类。

class People {
    constructor(name) { //构造函数
          this.name = name;
    }
    sayName() {
          console.log(this.name);
    }
}

class Student extends People {
    constructor(name, grade) { //构造函数
        super(name);    //调用父类构造函数
          this.grade = grade;
    }
    sayGrade() {
          console.log(this.grade);
    }
}

上面的例子中我们定义了一个 Student ,他是 People 的子类。

注意我们在 constructor 中是如何通过 super 调用父类的构造函数的。

getters & setters

现在我们可以通过 get 和 set 关键字来定义 getters 和 setters 了。

下面我们给 name 属性定义 getter 和 setter

class People {
    constructor(name) { //构造函数
          this.name = name;
    }
    get name() {
        return this._name.toUpperCase();
    }
    set name(name) {
        this._name = name;
    }
    sayName() {
          console.log(this.name);
    }
}
var p = new People("tom");
console.log(p.name);    //1
console.log(p._name);    //2
p.sayName();    //3

仔细看上面的例子,搞清楚最后三行分别会输出什么,就明白getter 和 setter该怎么用了。

主要是要区分 this._name 和 this.name 的区别。因为我们定义了 name 的读写器,而没有定义 _name 的读写器,所以访问这两个属性的结果是不同的。

但是要注意一点,不要这样写:

set name(name) {
    this.name = name;
}

因为给 this.name 赋值的时候会调用 set name ,这样会导致无限递归直到栈溢出。

静态方法

通过 static 关键字定义静态方法:

class People {
    constructor(name) { //构造函数
          this.name = name;
    }
    sayName() {
          console.log(this.name);
    }
    static formatName(name) {
        return name[0].toUpperCase() + name.sustr(1).toLowerCase();
    }
}

console.log(People.formatName("tom"));

静态方法一般用来提供一些工具方法。

私有属性

ES6并没有提供对私有属性的语法支持,但是我们可以通过闭包来实现私有属性。

关于 WeakMap,会在后面讲解。 为什么要用WeakMap呢?因为WeakMap 用object作为key,并且是一个弱引用,也就是说,WeakMap对这个对象的引用并不会导致GA无法回收这个对象(GA计算对象引用数量的时候并不会计算弱引用)。

var People = (function() {
  var p = new WeakMap();
  class People {
    constructor(name) { //构造函数
          var privateProperties = {
        name: name
    };
    p.set(this, privateProperties);
    }
    sayName() {
          console.log(this.name);
    }

    get name() {
      return p.get(this).name;
    }
}
return People;
})();

var p = new People("tom");
console.log(p.name);
p.sayName();

var p2 = new People("bob");
console.log(p2.name);
p2.sayName();

除了用WeakMap,还可以用闭包+Symbol来实现私有属性,参见后面专门讲Symbol的文章。