zoukankan      html  css  js  c++  java
  • javascript ES 6 class 详解

    Introduction

    上篇文章大致介绍了一些ES6的特性,以及如何在低版本浏览器中使用它们。本文是对class的详解。
    译自Axel Rauschmayer的Classes in ECMAScript 6
    另外,如果只是想测试ES6,可以到这个网站

    Overview

    借助class 我们可以写出这样的代码:

       class Point {
            constructor(x, y) {
                this.x = x;
                this.y = y;
            }
            toString() {
                return '(' + this.x + ', ' + this.y + ')';
            }
        }
        
        class ColorPoint extends Point {
            constructor(x, y, color) {
                super(x, y);
                this.color = color;
            }
            toString() {
                return super.toString() + ' in ' + this.color;
            }
        }
        
        let cp = new ColorPoint(25, 8, 'green');
        cp.toString(); // '(25, 8) in green'
        
        console.log(cp instanceof ColorPoint); // true
        console.log(cp instanceof Point); // true
    

    Base classes

    我们可以定义如下的class:

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

    我们可以像使用ES5标准中的constructor一样实例化class

        > var p = new Point(25, 8);
        > p.toString()
        '(25, 8)'
    

    实际上,class还是用function实现的,并没有为js创造一个全新的class体系。

        > typeof Point
        'function'
    

    但是,与function相比,它是不能直接调用的,也就是说必须得new出来

        > Point()
        TypeError: Classes can’t be function-called
    

    另外,它不会像function一样会被hoisted(原因是语义阶段无法解析到extends的内容)

        foo(); // works, because `foo` is hoisted
        function foo() {}
        new Foo(); // ReferenceError
        class Foo {}
    
        function functionThatUsesBar() {
            new Bar();
        }
        
        functionThatUsesBar(); // ReferenceError
        class Bar {}
        functionThatUsesBar(); // OK
    

    与函数一样,class的定义表达式也有两种,声明形式、表达式形式。之前用的都是声明形式,以下是表达式式的:

        const MyClass = class Me {
            getClassName() {
                return Me.name;
            }
        };
        let inst = new MyClass();
        console.log(inst.getClassName()); // Me
        console.log(Me.name); // ReferenceError: Me is not defined
    

    Inside the body of a class definition

    class定义体是只能包含方法,不能包含属性的(标准定义组织认为原型链中不应包含属性),属性被写在constructor中。以下是三种会用到的方法(constructor 、static method、 prototype method):

        class Foo {
            constructor(prop) {
                this.prop = prop;
            }
            static staticMethod() {
                return 'classy';
            }
            prototypeMethod() {
                return 'prototypical';
            }
        }
        let foo = new Foo(123);
    

    如下图([[Prototype]]代表着继承关系)当对象被new出来,拿的是Foo.prototype : Object分支,从而可以调prototype method

    constructor,这个方法本身,代表了class

        > Foo === Foo.prototype.constructor
        true
    

    constructor有时被称为类构造器。相较于ES5,它可以调用父类的constructor(使用super())。

    static methods。它们归属于类本身。

        > typeof Foo.staticMethod
        'function'
        > Foo.staticMethod()
        'classy'
    

    关于Getters and setters,它们的语法如下:

        class MyClass {
            get prop() {
                return 'getter';
            }
            set prop(value) {
                console.log('setter: '+value);
            }
        }
        > let inst = new MyClass();
        > inst.prop = 123;
        setter: 123
        > inst.prop
        'getter'
    

    方法名是可以动态生成的

        class Foo() {
            myMethod() {}
        }
        
        class Foo() {
            ['my'+'Method']() {}
        }
        
        const m = 'myMethod';
        class Foo() {
            [m]() {}
        }
    
    

    增加了迭代器的支持,需要给方法前面加一个*

        class IterableArguments {
            constructor(...args) {
                this.args = args;
            }
            * [Symbol.iterator]() {
                for (let arg of this.args) {
                    yield arg;
                }
            }
        }
        
        for (let x of new IterableArguments('hello', 'world')) {
            console.log(x);
        }
        
        // Output:
        // hello
        // world
    

    Subclassing

    通过extends,我们可以继承其它实现constructor的函数或对象。需要注意一下,constructor与非constructor调用父类方法的途径是不同的。

        class Point {
            constructor(x, y) {
                this.x = x;
                this.y = y;
            }
            toString() {
                return '(' + this.x + ', ' + this.y + ')';
            }
        }
        
        class ColorPoint extends Point {
            constructor(x, y, color) {
                super(x, y); // (A)
                this.color = color;
            }
            toString() {
                return super.toString() + ' in ' + this.color; // (B)
            }
        }
        > let cp = new ColorPoint(25, 8, 'green');
        > cp.toString()
        '(25, 8) in green'
        
        > cp instanceof ColorPoint
        true
        > cp instanceof Point
        true
    

    子类的原型就是它的父类

        > Object.getPrototypeOf(ColorPoint) === Point
        true
    

    所以,static method也被继承了

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

    static方法也是支持调用父类的。

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

    关于子类中使用构造器,需要注意的是,调用this之前,需要调用super()

        class Foo {}
        
        class Bar extends Foo {
            constructor(num) {
                let tmp = num * 2; // OK
                this.num = num; // ReferenceError
                super();
                this.num = num; // OK
            }
        }
    

    constructors是可以被显示覆盖(override)的。

        class Foo {
            constructor() {
                return Object.create(null);
            }
        }
        console.log(new Foo() instanceof Foo); // false
    

    如果基类中不显示定义constructor,引擎会生成如下代码

        constructor() {}
    

    对于子类

        constructor(...args) {
            super(...args);
        }
    

    The details of classes

    • 类名不能为eval 或者 arguments,不能有重复的类名,constructor不支持getter,setter。
    • classes不能像函数一样调用。
    • 原型方法不能用作构造器:
        class C {
            m() {}
        }
        new C.prototype.m(); // TypeError
    

    The details of subclassing

    ES 6中,子类的使用方法如下:

        class Point {
            constructor(x, y) {
                this.x = x;
                this.y = y;
            }
            ···
        }
    
        class ColorPoint extends Point {
            constructor(x, y, color) {
                super(x, y);
                this.color = color;
            }
            ···
        }
    
        let cp = new ColorPoint(25, 8, 'green');
    

    原型链实现:

    > const getProto = Object.getPrototypeOf.bind(Object);
    
    > getProto(Point) === Function.prototype
    true
    > getProto(function () {}) === Function.prototype
    true
    
    > getProto(Point.prototype) === Object.prototype
    true
    > getProto({}) === Object.prototype
    true
    
  • 相关阅读:
    网址
    123
    工具安装
    博客专栏-计算机网络
    JQuery(1)
    HTML常用标签
    Spring的线程池技术:ThreadPoolTaskExecutor
    Error:java: 程序包lombok不存在- IDEA+maven+lombok
    Andriod Studio中新创建的xml布局文件无法在R.layout中调用
    SAST : Single-Shot Arbitrarily-Shaped Text Detector论文阅读笔记
  • 原文地址:https://www.cnblogs.com/E-WALKER/p/4796278.html
Copyright © 2011-2022 走看看