• 第11章 代码模块化


    1. 在ES6之前的版本中模块化代码

    • 每个模块系统至少应该能够执行一下操作:
      • 定义模块接口,通过接口可以调用模块的功能
      • 隐藏模块的内部实现,使模块的使用者不需要关注模块内部的实现细节。同时,吟唱模块的内部实现,避免有可能产生的副作用和对bug的不必要修改

    1.1 使用对象、闭包和立即执行函数实现模块

    使用函数作为模块

    (function countClicks() {
        let numClicks = 0;  // 这个变量只有通过事件处理器调用,屏蔽了外部访问
        // 事件处理器创建的闭包保持局部变量numClicks活跃
        document.addEventListener("click", () => {
            numClicks++;
            console.log(numClicks);
        });
    })();
    // 暂时无法满足模块的第一个要求:接口
    

    模块模式:使用函数扩展模块,使用对象实现接口

    // 本例同样使用立即执行函数,
    // 但通过返回对象的方式将可以暴露的内容返给了MouseCounterModule变量
    // 使其成为一个接口,可以访问内部功能
    // 模块内部细节可以通过接口创建的闭包保持活跃
    const MouseCounterModule = function() {
        let numClick = 0;
        const handleClick = () => {
            console.log(++numClick);
        }
    
        const print = message => console.log(message);
    
        return {
            countClicks: () => {
                document.addEventListener("click", handleClick);
            },
            print: print
        };
    }();    // 立即执行函数
    
    MouseCounterModule.countClicks();
    MouseCounterModule.print("Hello!");
    // Hello!
    

    模块扩展

    // 使用立即执行函数
    // 将要扩展的模块作为参数传入函数
    (function(module) {
        let numScroll = 0;
        const handleScroll = () => {
            console.log(++numScroll);
        }
    
        // 将要添加的功能添加到传入模块当中
        module.countScroll = () => {
            document.addEventListener("wheel", handleScroll);
        }
    })(MouseCounterModule);
    
    MouseCounterModule.countScroll();
    

    通过模块扩展无法共享模块的私有变量
    当开始创建模块化应用时,模块本身常常依赖其他模块的功能,而模块模式无法实现这些依赖关系。

    1.2 使用AMD和CommonJS模块化JS代码

    AMD

    • 设计明确基于浏览器
    • 自动处理依赖,无需考虑模块引入的顺序
    • 异步加载模块,避免阻塞
    • 在同一文件夹中可以定义多个模块

    CommonJS

    • 基于文件,面向通用JS环境,不显式支持浏览器环境
    • 一个文件就是一个模块,文件中的代码就是模块的一部分,不需要使用立即执行函数来包装变量
    • 语法简单,只需定义module.exports属性,其余与标准代码无差异,引用模块只需使用require函数
    • 是Node.js默认的模块格式,所以可以使用npm无数的包

    2. ES6模块

    导出和导入功能

    在浏览器环境中使用时,文件类型需要设置为module

    <script src="./js/index.js" type="module"></script>
    
    // info.js
    const name = "Wango";
    
    // 单独导出内容
    export const age = 24;
    
    export function say(message){
        console.log(message);
    }
    // 或者
    const name = "Wango";
    
    const age = 24;
    
    function say(message){
        console.log(message);
    }
    
    export {age, say}; // 推荐
    
    
    // index.js
    
    // 导入的内容必须用大括号包起来
    // 路径是字符串且必须以.或./或../开头
    import { say } from "./info.js";
    
    say("Hello!");
    // Hello!
    
    // 导入这个文件全部标识符,且取个别名(不用大括号)
    import * as info from "./info.js";
    
    info.say("Hello!!!");
    // Hello!!!
    

    默认导出

    // Student.js
    // 定义默认导出
    export default class Student {
        constructor(name, age) {
            this.name = name;
            this.age = age;
        }
        info() {
            return `Name: ${this.name} | Age: ${this.age}`;
        }
    }
    // 默认导出的同时也可以导出指定内容
    export function say(msg) {
        console.log(msg);
    }
    
    // index.js
    // 导入默认导出的内容不需要大括号,也可以起别名
    import Stu from "./Student.js";
    
    const s1 = new Stu("Wango", 24);
    console.log(s1.info());
    // Name: Wango | Age: 24
    
    // 同时导入默认导出和普通导出
    import Stu, { say } from "./Student.js";
    
    const s1 = new Stu("Wango", 24);
    console.log(s1.info());
    // Name: Wango | Age: 24
    
    say("Hello!");
    // hello
    

    导入或导出时使用重命名

    // Students.js
    export default class Student {
        constructor(name, age) {
            this.name = name;
            this.age = age;
        }
        info() {
            return `Name: ${this.name} | Age: ${this.age}`;
        }
    }
    
    function say(msg) {
        console.log(msg);
    }
    
    // 用as设置别名
    export {say as sayHello};
    
    // index.js
    import Stu, { say as sayHi } from "./Student.js";
    
    const s1 = new Stu("Wango", 24);
    console.log(s1.info());
    // Name: Wango | Age: 24
    
    sayHi("Hello!");
    // hello
    

    使用as设置了别名之后就只能访问别名,不能访问原始的标识符

  • 相关阅读:
    go1.13 mod 实践和常见问题
    etcd 添加用户,授权特定目录
    golang 你所不知道的 log 和 fmt
    redis 原理系列之--字符串存储的实现原理(1)
    golang 写文件--详细解释
    面向对象范式的核心本质是?---不是继承 不是封装也不是多态
    关于自控力和拖延 的一点分享--《自控力》
    Linux 精确判断是否同一文件--及终端获取字符串md5 的值
    ARM版本及系列
    技术团队塑造
  • 原文地址:https://www.cnblogs.com/hycstar/p/14051097.html
Copyright © 2020-2023  润新知