ES6第六课、Class

作者: 前端一菜鸟 | 来源:发表于2019-04-04 09:27 被阅读2次

    ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。
    基本上,ES6 的class可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已

    简介

    类的由来

    JavaScript 语言中,生成实例对象的传统方法是通过构造函数。下面是一个例子

    function Point(x, y) {
      this.x = x;
      this.y = y;
    }
    
    Point.prototype.toString = function () {
      return '(' + this.x + ', ' + this.y + ')';
    };
    
    var p = new Point(1, 2);
    

    上面这种写法跟传统的面向对象语言(比如 C++ 和 Java)差异很大,很容易让新学习这门语言的程序员感到困惑。
    ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。

    class Point {
      constructor(x, y) {
        this.x = x;
        this.y = y;
      }
    
      toString() {
        return '(' + this.x + ', ' + this.y + ')';
      }
    }
    

    上面代码定义了一个“类”,可以看到里面有一个constructor方法,这就是构造方法,而this关键字则代表实例对象。也就是说,ES5 的构造函数Point,对应 ES6 的Point类的构造方法。
    Point类除了构造方法,还定义了一个toString方法。注意,定义“类”的方法的时候,前面不需要加上function这个关键字,直接把函数定义放进去了就可以了。另外,方法之间不需要逗号分隔,加了会报错。
    ES6 的类,完全可以看作构造函数的另一种写法。

    class Point {
      // ...
    }
    
    typeof Point // "function"
    Point === Point.prototype.constructor // true
    

    上面代码表明,类的数据类型就是函数,类本身就指向构造函数。
    使用的时候,也是直接对类使用new命令,跟构造函数的用法完全一致。

    class Bar {
      doStuff() {
        console.log('stuff');
      }
    }
    
    var b = new Bar();
    b.doStuff() // "stuff"
    

    静态属性

    静态属性指的是 Class 本身的属性,即Class.propName,而不是定义在实例对象(this)上的属性。

    class Foo {
    }
    
    Foo.prop = 1;
    Foo.prop // 1
    

    上面的写法为Foo类定义了一个静态属性prop。
    目前,只有这种写法可行,因为 ES6 明确规定,Class 内部只有静态方法,没有静态属性。现在有一个提案提供了类的静态属性,写法是在实例属性法的前面,加上static关键字。

    class MyClass {
      static myStaticProp = 42;
    
      constructor() {
        console.log(MyClass.myStaticProp); // 42
      }
    }
    

    推荐写法:上面的那种,这个新写法大大方便了静态属性的表达。

    // 老写法
    class Foo {
      // ...
    }
    Foo.prop = 1;
    
    // 新写法
    class Foo {
      static prop = 1;
    }
    

    老写法的静态属性定义在类的外部。整个类生成以后,再生成静态属性。这样让人很容易忽略这个静态属性,也不符合相关代码应该放在一起的代码组织原则。

    私有方法和私有属性

    私有方法和私有属性,是只能在类的内部访问的方法和属性,外部不能访问。这是常见需求,有利于代码的封装,但 ES6 不提供,只能通过变通方法模拟实现。

    一种做法是在命名上加以区别。

    class Widget {
    
      // 公有方法
      foo (baz) {
        this._bar(baz);
      }
    
      // 私有方法
      _bar(baz) {
        return this.snaf = baz;
      }
    
    }
    

    上面代码中,_bar方法前面的下划线,表示这是一个只限于内部使用的私有方法。但是,这种命名是不保险的,在类的外部,还是可以调用到这个方法。

    私有属性的提案

    目前,有一个提案,为class加了私有属性。方法是在属性名之前,使用#表示。

    class IncreasingCounter {
      #count = 0;
      get value() {
        console.log('Getting the current value!');
        return this.#count;
      }
      increment() {
        this.#count++;
      }
    }
    

    上面代码中,#count就是私有属性,只能在类的内部使用(this.#count)。如果在类的外部使用,就会报错。

    const counter = new IncreasingCounter();
    counter.#count // 报错
    counter.#count = 42 // 报错
    

    上面代码在类的外部,读取私有属性,就会报错。
    这种写法不仅可以写私有属性,还可以用来写私有方法。

    class Foo {
      #a;
      #b;
      constructor(a, b) {
        this.#a = a;
        this.#b = b;
      }
      #sum() {
        return #a + #b;
      }
      printSum() {
        console.log(this.#sum());
      }
    }
    

    上面代码中,#sum()就是一个私有方法。
    私有属性和私有方法前面,也可以加上static关键字,表示这是一个静态的私有属性或私有方法。

    class FakeMath {
      static PI = 22 / 7;
      static #totallyRandomNumber = 4;
    
      static #computeRandomNumber() {
        return FakeMath.#totallyRandomNumber;
      }
    
      static random() {
        console.log('I heard you like random numbers…')
        return FakeMath.#computeRandomNumber();
      }
    }
    
    FakeMath.PI // 3.142857142857143
    FakeMath.random()
    // I heard you like random numbers…
    // 4
    FakeMath.#totallyRandomNumber // 报错
    FakeMath.#computeRandomNumber() // 报错
    

    相关文章

      网友评论

        本文标题:ES6第六课、Class

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