• ES6快速入门(三)类与模块


    类与模块

    一、类

    一)类的声明

    class Person {
        constructor(name) {
            this.name = name;
        }
        sayName() {
            console.log(this.name);
        }
    }
    
    let tom = new Person('Tom');
    tom.sayName(); //Tom
    console.log(tom instanceof Person); //true
    console.log(tom instanceof Object); //true
    console.log(typeof Person); //function

    自有属性:属性只出现在实例而不是在原型上,而且只能由构造函数和方法来创建。

    差异:

    1. 类声明和函数定义不同,它们是不会被提升的。类声明的行为和 let 比较相似,所以当执
    行流作用到类声明之前类会存在于暂存性死区(temporal dead zone) 内。
    2. 类声明中的代码自动运行在严格模式下,同时没有任何办法可以手动切换到非严格模
    式。
    3. 所有的方法都是不可枚举的(non-enumerable) ,这和自定义类型相比是个显著的差
    异,因为后者需要使用 Object.defineProperty() 才能定义不可枚举的方法。
    4. 所有的方法都不能使用 new 来调用,因为它们没有内部方法 [[Construct]]
    5. 不使用 new 来调用类构造函数会抛出错误。
    6. 试图在方法内部重写类名的行为会抛出错误。 

    二)类表达式

    设计类表达式的目的主要是为了将它赋值给变量或者传参给函数。

    //不会被提升
    let Person = class {
        constructor(name) {
            this.name = name;
        }
    
        sayName() {
            console.log(this.name);
        }
    };

    三)作为一等公民的类

    在编程中,如果某些东西能作为值使用,那么它就被称为一等公民。ES6中类也是一等公民:

    function createPerson(person) {
        return new person();
    }
    let tom = createPerson(class {
       sayHi() {
           console.log('Hi');
       }
    });
    tom.sayHi(); //Hi

    类表达式另一个有趣的使用方式是通过立即调用(immediately invoking) 类构造函数来创建单例(singleton):

    let tom = new class {
        constructor(name) {
            this.name = name;
        }
        sayName() {
            console.log(`My name is ${this.name}`);
        }
    }('Tom');
    tom.sayName();

    四)访问器属性

    class Person {
        constructor(name) {
            this.name = name;
        }
        //这里不能用get phone(){}
        get phone2() {
            return this.phone;
        }
        set phone2(phoneNumber) {
            this.phone = phoneNumber;
        }
    }
    let price = new Person('Price', 112);
    price.name = 'Price2';
    price.phone = 119;
    console.log(`His name is ${price.name} and his phone number is ${price.phone}`);

    五)静态成员

    //静态成员不能被实例访问。你必须通过类本身来使用它们。
    class Person {
        constructor(name) {
            this.name = name;
        }
        sayName() {
            console.log(this.name)
        }
        //等同于Person.whatIs(){}
        static whatIs() {
            return 'I am a person!';
        }
    }

    六)继承

    class Worker extends Person {
        /*如果在派生类中定义 constructor 则必须使用super(),
        否则会发生错误。如果你选择不使用 constructor,
        那么会自动调用 super() 和传入构造函数的参数以创建类的实例*/
        constructor(name, age) {
            super(name);
            this.age = age;
        }
        //注意
        syaName() {
            super.sayName();
            console.log(`My name is ${this.name}`);
        }
        sayAge (){
            console.log(`I am ${this.age}`)
        }
    }
    
    let jimmy = new Worker('Jimmy', 2);
    jimmy.sayAge(); //I am 2
    jimmy.syaName(); //Jimmy   My name is Jimmy

    注意: 使用 super() 需要牢记以下几点:
    1. 你只能在派生类中使用 super(),否则(没有使用 extends 的类或函数) 一个错误会
    被抛出。
    2. 你必须在构造函数的起始位置调用 super(),因为它会初始化 this。任何在 super()
    之前访问 this 的行为都会造成错误。
    3. 在类构造函数中,唯一能避免调用 super() 的办法是返回一个对象。

    ECMAScript 6 派生类最强大的地方在于它们可以继承一个表达式。只要该表达式的计算
    结果包含 [[Construct]] 的函数和一个原型,那么就可以使用 extends 来继承它。

    内置对象的继承

    使用ES5很难继承内置对象,ES6做法:

    class MyArray extends Array {
    }

    二、模块

    ECMAScript 6 之前,每个 JavaScript 文件中定义的内容都由全局作用域共享。
    web 应用变得复杂并需要书写更多的 JavaScript 代码时,上述加载方式会出现命名冲突或安全方面的问题。

    模块是指采取不同于现有加载方式的 JavaScript 文件(与 script 这种传统的加载模式相
    对) 。这种方式很有必要,因为它和 script 使用不同的语义:
    1. 模块中的代码自动运行在严格模式下,并无任何办法修改为非严格模式。
    2. 模块中的顶级(top level) 变量不会被添加到全局作用域中。它们只存在于各自的模块中
    的顶级作用域。
    3. 模块顶级作用域中的 this undefined
    4. 模块不允许存在 HTML 式的注释(JavaScript 历史悠久的遗留特性) 。
    5. 模块必须输出可被模块外部代码使用的相关内容。
    6. 模块可能会引入其它模块中的绑定。

    模块真正的好处在于可以输出和引入需要的绑定,而不是文件中的所有内容。

    理解输出和引入是领悟模块与 script 之间差异的基础。 

    一)导出(export)

    可以使用export关键字将已发布的代码部分公开给其他模块。例如:

        // 导出数据
        export var color = "red";
        export let name = "Nicholas";
        export const magicNumber = 7;
        // 导出函数
        export function sum(num1, num2) {
            return num1 + num1;
        } 
    /
    / 导出类 export class Rectangle { constructor(length, width) { this.length = length; this.width = width; } } // 此函数为模块私有 function subtract(num1, num2) { return num1 - num2; } // 定义一个函数…… function multiply(num1, num2) { return num1 * num2; } // ……稍后将其导出 export { multiply };

    二)导入

    一旦你有了包含导出的模块,就能在其他模块内使用 import 关键字来访问已被导出的功能:

    import { identifier1, identifier2 } from "./example.js";
    // 完全导入
    import * as example from "./example.js";

    当从模块导入了一个绑定时,该绑定表现得就像使用了 const 的定义。这意味着你不能再定
    义另一个同名变量(包括导入另一个同名绑定) ,也不能在对应的 import 语句之前使用此
    标识符(也就是要受暂时性死区限制) ,更不能修改它的值。

        export var name = "Nicholas";
        export function setName(newName) {
            name = newName;
        }
    import { name, setName } from "./example.js";
    console.log(name); // "Nicholas"
    setName("Greg");
    console.log(name); // "Greg"
    name = "Nicholas"; // error

    调用 setName("Greg") 会回到导出 setName() 的模块内部,并在那里执行,从而将 name
    置为 "Greg" 。注意这个变化会自动反映到所导入的 name 绑定上,这是因为绑定的 name
    是导出的 name 标识符的本地名称,二者并非同一个事物。

    外部模块导入的 name 变量与在 example.js 模块内部的 name 变量对比,
    前者是对于后者的只读引用,会始终反映出后者的变化。就算后者的值在负责导出的模块中发生了变化,
    这种绑定关系也不会被破坏。模块导出与导入的绑定机制,与写在一个文件或模块内的代码是不同的。

    三)重命名

    function sum(num1, num2) {
        return num1 + num2;
    } 
    export { sum as add };

    此时必须使用:

    import { add } from "./example.js";

    导入重命名:

    import { add as sum } from "./example.js";

    四)再导出

    import { sum } from "./example.js";
    export { sum }

    五)在Web浏览器使用模块

    <!-- this will execute first -->
    <script type="module" src="module1.js"></script>
    <!-- this will execute second -->
    <script type="module">
    import { sum } from "./example.js";
    let result = sum(1, 2);
    </script>
    <!-- this will execute third -->
    <script type="module" src="module2.js"></script>
    <script type="module" async src="module1.js"></script>
    <script type="module" async src="module2.js"></script>
    Simple is important!
  • 相关阅读:
    配置IIS Express 7.5以允许外部访问
    免费CDN /初体验 访问量激升19%
    微软发布IIS Express:Visual Studio全新内置的Web服务器
    Visual Studio智能提示突然消失的解决办法 (vs2008 vs2010 vs2012 智能提示)
    深入理解HTTP协议
    TSO、UFO、GSO、LRO、GRO和RSS介绍
    MERGE表的问题
    使用zypper安装软件
    Mysql遇到Too many connections的解决办法
    处理SecureCRT中使用vim出现中文乱码问题
  • 原文地址:https://www.cnblogs.com/Shadowplay/p/9888299.html
Copyright © 2020-2023  润新知