es6_类(class)

创建类

通过class关键字进行创建

类的数据类型就是函数,类本身指向构造函数

        class Bar {
            doStuff() {
                console.log('stuff');
            }
        }

        var b = new Bar();
        b.doStuff(); //stuff
        console.log(typeof Bar); //function
        console.log(Bar === Bar.prototype.constructor); //true
        function Bar() {

        }
        Bar.prototype = {
            constructor: Bar,
            doStuff() {
                console.log('stuff');
            }
        }
        var b = new Bar();
        b.doStuff(); //stuff

由上面的代码可以看出,类的数据类型就是函数,类本身就是构造函数,class更具体来说就是es6的语法糖,起到与构造函数相同的作用。

类的所有方法都定义在类的prototype属性上,在类的实例上调用方法实际上是调用原型对象上的方法

        class Point {
            constructor() {
                // ...
            }

            toString() {
                // ...
            }

            toValue() {
                // ...
            }
        }

        // 等同于

        Point.prototype = {
            constructor() {},
            toString() {},
            toValue() {},
        };
        class B {
            toValue() {}
        }
        let b = new B();

        console.log(b.toValue === B.prototype.toValue); //true

通过object.assign向类添加方法

        class Point {
            constructor() {}
        }

        Object.assign(Point.pototype, {
            toString() {},
            toValue() {}
        })

类内部的所有定义方法都是不可枚举的

        class Point {
            constructor() {}
            toString() {}
        }

        console.log(Object.keys(Point.prototype)); //[]
        console.log(Object.getOwnPropertyNames(Point.prototype)); //["constructor","toString"]

constructor方法

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

class Point{}
//等同于
class Point{
      constructor(){}
}

写在constructor函数中的代码相当于写在构造函数本身中,即Point.prototype.constructor

没有写在constructor函数中的代码,相当于写在原型对象中,即Point.prototype

类的实例

类只能通过new来进行调用,且所有的类的实例共享一个原型对象

        class Foo {
            constructor() {}
        }
        var foo1 = new Foo();
        var foo2 = new Foo();
        console.log(foo1.__proto__ == foo2.__proto__); //true
        //允许通过实例的__proto__属性对原型对象进行CRUD操作,其一经修改,所有的实例都会受到影响

取值函数(getter)与存值函数(setter)

        class myClass {
            constructor() {}
            get prop() {
                return 'getter';
            }
            set prop(val) {
                console.log('setter: ' + val);
            }
        }

        let inst = new myClass();
        inst.prop = 123;
        console.log(inst.prop);

上面代码中,prop属性有对应的存值函数和取值函数,因此赋值和读取行为都被自定义了。
在ES5中有Object.getOwnPropertyDescriptor方法,用于获取指定对象的访问器属性或数据属性。

        var descriptor = Object.getOwnPropertyDescriptor(myClass.prototype, 'prop');
        console.log("get" in descriptor); //true
        console.log("set" in descriptor); //true

属性表达式

类的属性名,可以采用表达式

        let methodName = 'getArea';
        class Foo {
            constructor() {}
                [methodName]() {
                    console.log('xxx');
                }
        }

        var foo = new Foo();
        foo.getArea(); //'xxx'

Class表达式

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

        let inst = new myClass();
        console.log(inst.getClassName()); //Me
        //在class外部,这个类只能使用myClass引用
        //Me只在class内部有定义

通过class表达式立即执行class

        let person = new class {
            constructor(name) {
                this.name = name;
            }

            sayName() {
                console.log(this.name);
            }
        }('张三');

        person.sayName(); //张三
  • 严格模式

类和模块内部默认严格模式,所以不需要使用'use strict'指定运行模式

  • 不存在提升

类不存在变量提升,即 class Foo{} 与 new Foo() 的顺序不能搞混

  • name属性

ES6的类本身只是ES5的构造函数的包装,因此可以通过 Foo.name 得到 class Foo{} 的name属性(即Foo)

  • Generator方法

如果某个方法之前加上星号(*),就表示该方法是一个 Generator 函数。

  • this指向

类的方法内部如果含有this,它默认指向类的实例。

静态方法

静态方法不会被实例继承

类相当于实例的原型对象,所有在类中定义的方法都会被实例继承,但是在一个方法前加上static关键字,就表示该方法不会被实例继承,而是通过类来进行调用,这种方法被称为“静态方法”.

        class Foo {
            static classMethod() {
                return 'hello';
            }
        }
        console.log(Foo.classMethod()); //hello
        var foo = new Foo();
        console.log(foo.classMethod()); //foo.classMethod is not a function

静态方法的this指向类

如果静态方法包含this关键字,此时this指向的是类。(静态方法可以和非静态方法重名)

        class Foo {
            static bar() {
                this.baz();
            }
            baz() {
                console.log('world');
            }
            static baz() {
                console.log('hello');
            }
        }
        Foo.bar(); //hello

父类的静态方法可以被子类继承,但需要通过子类的类来进行调用

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

        }
        console.log(Bar.classMethod());

静态方法也可以从super对象上调用。

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

        class Bar extends Foo {
            static classMethod() {
                return super.classMethod() + ', too';
            }
        }
        console.log(Bar.classMethod());

实例属性的新写法

实例属性可以定义在constructor()方法里面的this上面,也可以定义在类的最顶层。

        class IncreasingCounter {
            constructor() {
                this._count = 0;// 定义在这儿相当于定义在构造函数内
            }
            get value() {
                console.log('Getting the current value');
                return this._count;
            }
            increment() {
                this._count++;// 相当于定义在原型对象中
            }
        }
        var inc1 = new IncreasingCounter();
        var inc2 = new IncreasingCounter();
        inc1.increment();
        console.log(inc1.value); //Getting the current value 1
        console.log(inc2.value); //Getting the current value 0
        class IncreasingCounter {
            _count = 0;// 相当于定义在原型对象
            get value() {
                console.log('Getting the current value');
                return this._count;
            }
            increment() {
                this._count++;
            }
        }
        var inc1 = new IncreasingCounter();
        var inc2 = new IncreasingCounter();
        inc1.increment();
        console.log(inc1.value);
        console.log(inc2.value);

写在类的顶端的属性和写在constructor方法中的属性是有区别的。写在类的顶端的属性相当于写在类的原型对象内,而写在constructor方法中的属性则是写在构造函数中的。

静态属性

class MyClass {
    static myStaticProp = 45;
    constructor() {
        this.getVal = function () {
            console.log(MyClass.myStaticProp);
        }
    }
}
var c = new MyClass();
c.getVal(); //45

类的静态属性只属于类,与实例无关

posted @ 2020-08-05 22:50  Syinho  阅读(209)  评论(0编辑  收藏  举报