美文网首页
es6-class的使用

es6-class的使用

作者: 燕_梦 | 来源:发表于2018-01-29 14:19 被阅读0次

    1\class的简介:
    ES6 的类,完全可以看作构造函数的另一种写法。

    class Point {
    // ...
    }

    typeof Point // "function"
    Point === Point.prototype.constructor // true
    上面代码表明,类的数据类型就是函数,类本身就指向构造函数。
    eg:react就是用了es6的方法:
    export default class MobileFooter extends React.Component {
    render() {
    return (
    <footer>
    <Row>
    <Col span={2}></Col>
    <Col span={20} class="footer">
    © 2016 ReactNews. All Rights Reserved.
    </Col>
    <Col span={2}></Col>
    </Row>
    </footer>
    );
    };
    }

    2\constructor 方法
    constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加。

    class Point {
    }

    // 等同于
    class Point {
    constructor() {}
    }
    上面代码中,定义了一个空的类Point,JavaScript 引擎会自动为它添加一个空的constructor方法。

    类必须使用new调用,否则会报错。这是它跟普通构造函数的一个主要区别,后者不用new也可以执行。

    class Foo {
    constructor() {
    return Object.create(null);
    }
    }

    Foo()
    // TypeError: Class constructor Foo cannot be invoked without 'new'

    3\类的实例对象
    生成类的实例对象的写法,与 ES5 完全一样,也是使用new命令。前面说过,如果忘记加上new,像函数那样调用Class,将会报错。

    class Point {
    // ...
    }

    // 报错
    var point = Point(2, 3);

    // 正确
    var point = new Point(2, 3);

    4\Class 表达式
    与函数一样,类也可以使用表达式的形式定义。

    const MyClass = class Me {
    getClassName() {
    return Me.name;
    }
    };

    5\私有方法
    方法1:_bar,下划线
    私有方法是常见需求,但 ES6 不提供,只能通过变通方法模拟实现。

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

    class Widget {

    // 公有方法
    foo (baz) {
    this._bar(baz);
    }

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

    // ...
    }
    方法2:将方法移除class:
    另一种方法就是索性将私有方法移出模块,因为模块内部的所有方法都是对外可见的。

    class Widget {
    foo (baz) {
    bar.call(this, baz);
    }

    // ...
    }

    function bar(baz) {
    return this.snaf = baz;
    }

    方法3:利用Symbol值的唯一性,将私有方法的名字命名为一个Symbol值
    const bar = Symbol('bar');
    const snaf = Symbol('snaf');

    export default class myClass{

    // 公有方法
    foo(baz) {
    thisbar;
    }

    // 私有方法
    bar {
    return this[snaf] = baz;
    }

    // ...
    };
    上面代码中,bar和snaf都是Symbol值,导致第三方无法获取到它们,因此达到了私有方法和私有属性的效果。

    私有属性的提案

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

    class Point {
      #x;
    
      constructor(x = 0) {
        #x = +x; // 写成 this.#x 亦可
      }
    
      get x() { return #x }
      set x(value) { #x = +value }
    }
    
    

    上面代码中,#x就表示私有属性x,在Point类之外是读取不到这个属性的。还可以看到,私有属性与实例的属性是可以同名的(比如,#xget x())。

    私有属性可以指定初始值,在构造函数执行时进行初始化。

    class Point {
      #x = 0;
      constructor() {
        #x; // 0
      }
    }
    
    

    之所以要引入一个新的前缀#表示私有属性,而没有采用private关键字,是因为 JavaScript 是一门动态语言,使用独立的符号似乎是唯一的可靠方法,能够准确地区分一种属性是否为私有属性。另外,Ruby 语言使用@表示私有属性,ES6 没有用这个符号而使用#,是因为@已经被留给了 Decorator。

    该提案只规定了私有属性的写法。但是,很自然地,它也可以用来写私有方法。

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

    上面代码中,#sum()就是一个私有方法。

    另外,私有属性也可以设置 getter 和 setter 方法。

    class Counter {
      #xValue = 0;
    
      get #x() { return #xValue; }
      set #x(value) {
        this.#xValue = value;
      }
    
      constructor() {
        super();
        // ...
      }
    }
    
    

    上面代码中,#x是一个私有属性,它的读写都通过get #x()set #x()来完成。

    6、this的指向问题
    this 的指向
    类的方法内部如果含有this,它默认指向类的实例。但是,必须非常小心,一旦单独使用该方法,很可能报错。

    class Logger {
    printName(name = 'there') {
    this.print(Hello ${name});
    }

    print(text) {
    console.log(text);
    }
    }

    const logger = new Logger();
    const { printName } = logger;
    printName(); // TypeError: Cannot read property 'print' of undefined
    上面代码中,printName方法中的this,默认指向Logger类的实例。但是,如果将这个方法提取出来单独使用,this会指向该方法运行时所在的环境,因为找不到print方法而导致报错。

    一个比较简单的解决方法是,在构造方法中绑定this,这样就不会找不到print方法了。

    class Logger {
    constructor() {
    this.printName = this.printName.bind(this);
    }

    // ...
    }
    另一种解决方法是使用箭头函数。

    class Logger {
    constructor() {
    this.printName = (name = 'there') => {
    this.print(Hello ${name});
    };
    }

    // ...
    }
    还有一种解决方法是使用Proxy,获取方法的时候,自动绑定this。

    function selfish (target) {
    const cache = new WeakMap();
    const handler = {
    get (target, key) {
    const value = Reflect.get(target, key);
    if (typeof value !== 'function') {
    return value;
    }
    if (!cache.has(value)) {
    cache.set(value, value.bind(target));
    }
    return cache.get(value);
    }
    };
    const proxy = new Proxy(target, handler);
    return proxy;
    }

    const logger = selfish(new Logger());
    9、静态方法:
    Class 的静态方法
    类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。

    class Foo {
    static classMethod() {
    return 'hello';
    }
    }

    Foo.classMethod() // 'hello'

    var foo = new Foo();
    foo.classMethod()
    // TypeError: foo.classMethod is not a function
    上面代码中,Foo类的classMethod方法前有static关键字,表明该方法是一个静态方法,可以直接在Foo类上调用(Foo.classMethod()),而不是在Foo类的实例上调用。如果在实例上调用静态方法,会抛出一个错误,表示不存在该方法。

    注意,如果静态方法包含this关键字,这个this指的是类,而不是实例。

    相关文章

      网友评论

          本文标题:es6-class的使用

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