zoukankan      html  css  js  c++  java
  • chapter1.8、模块化

    模块化

    ES6之前,JS没有出现模块化系统。

    JS主要在前端的浏览器中使用,js文件下载缓存到客户端,在浏览器中执行。

    比如简单的表单本地验证,漂浮一个广告。

    服务器端使用ASP、JSP等动态网页技术,将动态生成数据嵌入一个HTML模板,里面夹杂着JS后

    使用 <script> 标签,返回浏览器端。

    这时候的JS只是一些简单函数和语句的组合。

    <html>
        <head>
            <title>magedu</title>
            <script src="./src/moda.js"></script>
        </head>
    
        <body>
                Welcome
                <script>
                    foo()
                    console.log(CONSTA)
                </script>
        </body>
            
    </html>

    在同一目录下建立src文件夹,文件夹下建立moda.js文件

    class A{
        constructor(x){
            this.x = x
        }
        show () {
            console.log(this.x)
        }
    }
    
    function foo() {
        console.log("foo function");
    }
    
    const CONSTA = "aaa"

    用浏览器打开html文件,在控制台就可以看到,浏览器下按F12.

    2005年之后,随着Google大量使用了AJAX技术之后,可以异步请求服务器端数据,带来了前端交互的巨大变化。

    前端功能需求越来越多,代码也越来也多。随着js文件的增多,灾难性的后果产生了。由于习惯了随便写,js脚本中各种全局变量污染,函数名冲突,无法表达脚本之间的依赖关系,因为都是用脚本文件先后加载来实现的。亟待模块化的出现。

    2008年V8引擎发布,2009年诞生了Nodejs,支持服务端JS编程,但没有模块化是不可以的。

    之后产生了commonjs规范。

    commonjs规范,使用全局require函数导入模块,使用exports导出变量。

    为了将这种模块化规范向前端开发迁移,又演化出其它的规范。例如AMD。

    AMD(Asynchronous Module Definition)异步模块定义,使用异步方式加载模块,模块的加载不影响它后面语句的执行。所有依赖这个模块的语句,都需要定义在一个回调函数,回调函数中使用模块的变量和函数,等模块加载完成之后,这个回调函数才会执行,就可以安全的使用模块的资源了。其实现就是AMD/RequireJs。AMD虽然是异步,但是会预先加载和执行。

    CMD(Common Module Definition),使用seajs,作者是淘宝前端玉伯,兼容并包解决了RequireJs的问题。

    CMD推崇as lazy as possible,尽可能的懒加载。

    由于社区的模块化呼声很高,ES6开始提供支持模块的语法,但是浏览器目前支持还不够。

    ES6模块化

    import语句,导入另一个模块导出的绑定。
    export语句,从模块中导出函数、对象、值的,供其它模块import导入用。

    导出

    建立一个模块目录src,然后在这个目录下新建一个moda.js,内容如下:

    export class A{
        constructor(x){
            this.x = x
        }
        show () {
            console.log(this.x)
        }
    }
    
    export function foo() {
        console.log("foo function");
    }
    
    export const CONSTA = "aaa"

    导入

    import {A,foo,CONSTA} from "./src/moda.js"
    
    foo()
    a = new A(23)
    console.log()

    VS Code可以很好的语法支持了,但是运行环境,包括V8引擎,都不能很好的支持模块化语法。

    工具链,使用JS工具。

    转译工具

    转译就是从一种语言代码转换到另一个语言代码,当然也可以从高版本转译到低版本的支持语句。

    由于JS存在不同版本,不同浏览器兼容的问题,使用transpiler转译工具解决

    babel

    开发中可以使用较新的ES6语法,通过转译器转换为指定的某些版本代码。

    官网 http://babeljs.io/

    参考文档 https://babeljs.io/docs/en/6.26.3/index.html

    注意当前版本7.x已经有了较大的变化,请参看6.x文档

    可以测试迭代器的实现,转换完的内容不需要关心。

    function * counter(){
      let i = 0;
      while(true)
      yield (++i);
    }
    g = counter();
    console.log(g.next().value);

    预设

    有如下一些预设presets,我们先看看有哪些,一会儿再进行预设的安装和配置

    presets:
    babel-preset-env 当前环境支持的代码,新target,全部包括es6,es2017,es测试版本等,只写这一个就可以了

    react转码规则

    $ npm install --save-dev babel-preset-react

    ES2015转码规则
    $ npm install --save-dev babel-preset-es2015

    ES7不同阶段语法提案的转码规则(共有4个阶段),选装一个
    $ npm install --save-dev babel-preset-stage-0
    $ npm install --save-dev babel-preset-stage-1
    $ npm install --save-dev babel-preset-stage-2
    $ npm install --save-dev babel-preset-stage-3

    离线转译安装配置

    1、初始化npm

    在项目目录中使用

    $ npm init

    一直回车,会在根目录下生成一个新文件package.json,内容就是之前回车提示输入的内容

    2、设置镜像

    .npmrc文件

    运行环境文件

    可以放到npm的目录下npmrc文件中,全局影响

    可以放到用户家目录中,影响用户

    可以放到项目根目录中,影响项目

    本次放到项目根目录中,内容如下

    因为国外速度较慢,使用淘宝的

    registry=https://registry.npm.taobao.org

    $ echo "registry=https://registry.npm.taobao.org" > .npmrc

    3、安装

    项目根目录下执行

    $ npm install babel-core babel-cli --save-dev

    --save-dev说明
    当你为你的模块安装一个依赖模块时,正常情况下你得先安装他们(在模块根目录下npm install module-name),然后连同版本号手动将他们添加到模块配置文件package.json中的依赖里(dependencies)。开发用。
    --save和--save-dev可以省掉你手动修改package.json文件的步骤。
    spm install module-name --save 自动把模块和版本号添加到dependencies部分
    spm install module-name --save-dev 自动把模块和版本号添加到devdependencies部分

    package.json 里边的 devDependencies ,后边的是开发用的依赖

    开发依赖前边去掉dev就是运行依赖,在打包时不要打包开发依赖

    安装完后,在项目根目录下出现 node_modules目录 ,里面有babel相关模块及依赖的模块。

    4、修改package.json

    替换 scripts 的部分  "test": "echo "Error: no test specified" && exit 1" 替换为 "build": "babel src -d lib"

    babel src -d lib 意思是从src目录中转译后的文件输出到lib目录

    5、准备目录

    项目根目录下建立src和lib目录。

    src 是源码目录;

    lib 是目标目录。

    6、配置babel和安装依赖

    在目录根目录下创建 .babelrc 文件,Json格式。

    {
        "presets": ["env"]
    }

    env 可以根据当前环境自动选择。

    安装依赖

     $ npm install babel-preset-env --save-dev

     7、准备js文件

     在src中的mod.js

    export class A{
        constructor(x){
            this.x = x
        }
        show () {
            console.log(this.x)
        }
    }
    
    export function foo() {
        console.log("foo function");
    }
    
    export const CONSTA = "aaa"

    src目录下新建index.js

    import {A,foo,CONSTA} from "./mod.js"
    
    foo()
    let a = new A(23)
    a.show()
    console.log(a,a.x,CONSTA)

    直接在VS Code的环境下执行出错。估计很难有能够正常运行的环境。所以,要转译为ES5的代码。
    在项目根目录下执行命令

     $ npm run build

    $ npm run build

    > my_test@1.0.0 build D:project	estjsmy_test
    > babel src -d lib
    
    srcindex.js -> libindex.js
    srcmod.js -> libmod.js

    转译成功

    运行

    $ node lib/index.js

    使用babel等转译器转译JS非常流行。

    开发者可以在高版本中使用新的语法特性,提高开发效率,把兼容性问题交给转译器处理

    导入导出

    说明:导出代码都在src/mod.js中,导入代码都写在src/index.js中。

    缺省导入导出

    只允许一个缺省导出,缺省导出可以是变量、函数、类,但不能使用let、var、const关键字作为默认导出

    // 缺省导出 匿名函数
    export default function() {
        console.log('default export function')
    }
    // 缺省导入
    import defaultFunc from './mod'
    defaultFunc();
    // 缺省导出 命名函数
    export default function xyz() {
        console.log('default export function')
    }
    
    // 缺省导入
    import defaultFunc from './mod'
    defaultFunc();

    缺省导入的时候,可以自己重新命名,可以不需要和缺省导出时的名称一致,但最好一致。

    缺省导入,不需要在import后使用花括号

    export class A{
        constructor(x){
            this.x = x
        }
        show () {
            console.log(this.x)
        }
    }
    
    export default function foo() {
        console.log("foo default function");
    }
    
    export const CONSTA = "aaa"
    import foo, {A,CONSTA}from  "./moda"
    
    foo()
    let a = new A(23)
    a.show()
    console.log(a,a.x,CONSTA)

    命名导入导出

    导出

    /**
    * 导出举例
    */
    // 缺省导出类
    export default class {
        constructor(x) {
            this.x = x;
        }   
        show(){
            console.log(this.x);
        }
    }
    
    // 命名导出 函数
    export function foo(){
        console.log('regular foo()');
    }
    
    // 函数定义
    function bar() {
        console.log('regular bar()');
    }
    
    // 变量常量定义
    let x = 100;
    var y = 200;
    const z = 300;
    // 导出
    export {bar, x, y, z};

    导入

    /**
    * ~~~~~~~~~~~~~~~
    * 导入举例
    * as 设置别名
    */
    import defaultCls, {foo, bar, x, y, z as CONST_C} from './moda';
    foo();
    bar();
    console.log(x); // x只读,不可修改,x++异常
    console.log(y); // y只读
    console.log(CONST_C);
    new defaultCls(1000).show();

    也可以使用下面的形式,导入所有导出,但是会定义一个新的名词空间。使用名词空间可以避免冲突。

    import * as newmod from './mod';
    newmod.foo(); newmod.bar();
    new newmod.default(2000).show();
  • 相关阅读:
    云小课 | 华为云KYON之VPC终端节点
    华为云专家向宇:工欲善其事必先利其器,才能做数据的“管家”
    NB-IoT四大关键特性及实现告诉你,为啥NB
    Base64 原理
    netty系列之:轻轻松松搭个支持中文的服务器
    轻松让你的nginx服务器支持HTTP2协议
    是的你没看错,HTTP3来了
    HTTP协议之:HTTP/1.1和HTTP/2
    netty系列之:在netty中使用protobuf协议
    protocol buffer的高效编码方式
  • 原文地址:https://www.cnblogs.com/rprp789/p/9978696.html
Copyright © 2011-2022 走看看