zoukankan      html  css  js  c++  java
  • ES6之module

    该博客原文地址:http://www.cnblogs.com/giggle/p/5572118.html

    一、module概述

    JavaScript一直没有模块体系,但是伴随着ES6的到来,module随之而来。

    ES6module的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入、输出变量。简而言之就是‘编译时加载’。

    ES6module相对来说实现得还是比较简单,易上手。

    ES6module提倡一个js文件就是一个模块的概念,主要包括两个命令:export和import,用于模块向外提供接口(export)和引入其他模块接口(import)。

    好了,下面就说下我说理解的export命令和import命令。

    注:学习ES6之module需要有个转换器,因为现在好多还没有支持ES6的module。见“ES6转换ES5

    二、export命令

    export命令说白了就是用于模块对外提供的接口。

    语法如下:

    var f = 1;
    export {f};

    或者

    export var f = 1;

    但是不能是下面这个样子:

    var f = 1;
    export f;

    为什么呢?

    需要注意ES6module是向外抛的值的引用,是引用(这和CommonJS模块不一样,CommonJS是向外抛的值的拷贝)

    所以,你像上面这样肯定不对嘛,因为export f就是向外抛的值了,不是引用咯。

    并且,还需要注意的是,export不是最后处理的哦,什么意思?

    比如test1:

    export {name};
    var name = 'Monkey';

    如上,这样其实向外抛的是空,如果用ES6module的import(import在下面会详情说到)引用它,会输出undefined。

    如下(利用import)test2:

    import {name} from './test';
    console.log(name);

    将test1和test2,利用babel转换成ES5后的代码如下:

    test1:

    test2:

    在node环境下运行test2,得下:

    所以,export在ES6module中,和代码一样依行执行。而不像ES6module中的import那样会将其提升到模块顶部,首先执行。

    三、import命令

    import命令说白了,就是引用export对外提供的接口。对,是引用,而不是赋值。

    import的用法如下:

    /*
        name为test.js文件中export往外抛的引用名,名字必须一一对应
        from后面的'./test'为你所引入模块的相对路径
    */
    import {name} from './test';

    其中,如果你想改变引用名,可以用as,如下:

    import {name as ourName} from './test';

    如果你想引入模块中的所有变量,可以利用通配符*,然后利用as自定义名称,如下:

    //引入test模块的所有抛出的引用,并将其存放在allVar中
    import * as allVar from './test';
    //随后,如果test模块中有one方法,我们可以这么使用
    allVar.one();

    像上面这些例子中,我们用import都需要明确指定模块中对应的引用名称,或者使用*全部引用。其实,我们还可以在export中设置default,这样import引用模块时,就不需要指定使用名啦。

    什么意思?

    如下:

    //test模块
    function getName(){
        console.log('Monkey');
    };
    //default其实就相当于ES6module为我们设定的一个名字,对应getName的值
    export default getName;
    
    //使用test模块,one是我随便起的名字,它就对应default,而不需要{}了
    import one from './test';
    四、升华

    ES6module输出的值是值的引用。我们可以通过一个demo,更透彻地认识这点。

    如下:

    //模块sample
    var i = 0;
    export {i};
    //模块test1,引入sample模块
    import {i} from './sample';
    i++;
    //模块test2,引入sample模块
    import {i} from './sample';
    console.log(i);
    //模块main,引入test1和test2模块
    import './test1';
    import './test2';

    利用bable转换:

    报错了!!在模块test1中的i++是只读的。(’i’ is read-only).

    原因就是:由于ES6输入的模块变量,只是一个”符号连接“,所以这个变量是只读的,对它进行重新赋值会报错。(摘自‘阮一峰—ECMAScript6入门’)。

    我们再修改下上面的代码,

    如下:

    利用bable转换如上代码后,利用cmd,运行main.js,得如下结果:

     

    我们在main.js中是利用import引入test1和test2模块,但是,从上面的结果可以看出,他们是引用的同一份sample。

    所以,ES6module输出的值是值的引用。且,因为ES6module输出的值是值的引用。所以当出现循环引用模块时,它和CommonJS是不一样的。

    如下,CommonJS’s Demo:

    注:CommonJS是值的拷贝,不是引用。

    main.js

    var y = require('./test');
    exports.b = 'dorie';
    setTimeout(function(){
        console.log(y.y);
    },2000); 

    test.js

    var b = require('./main');
    var y;
    setTimeout(function(){
        y = 'monkey' + b.b;
    },1000);  
    exports.y = y;  

    运行main.js,得下结果:

     

    Why?

    因为CommonJS是值的拷贝,当执行main.js时,引入test模块,将y的值赋值给main.js里的y变量,此时y是undefined,且已经赋值了,但test模块在1秒后运行setTimeout里的匿名函数后,y变为’monkey’ + b.b,可是对main.js里的y已经无影响,因为是值拷贝嘛。

    我们将上述代码换成ES6module的形式,如下:

    main.js

    import {y} from './test';
    export var b = 'dorie';
    setTimeout(function(){
        console.log(y);
    },2000);  

    test.js

    import {b} from './main';
    var y;
    setTimeout(function(){
        y = 'monkey' + b;
    },1000);  
    export {y}; 

    利用Bable将ES6module转换成ES5后,在node环境下运行转换后的main.js,得如下结果:

     

    其实逻辑与上述CommonJS是一样的,但是结果却不一样,原因就是ES6module是值的引用!!

  • 相关阅读:
    量身打造自己的MyEclipse(多图)
    DevExpress v17.2新版亮点—WPF篇(五)
    DevExpress WPF入门指南:绑定编辑器对话框
    MyEclipse 2017 Stable 2.0发布|附下载
    springmvc常用注解标签详解
    什么是SpringMVC?
    SpringBoot页面渲染
    怎样理解Spring的IOC和AOP?
    LESS 原理,一款css的预处理程序Less的使用
    移动端web app要使用rem实现自适应布局:font-size的响应式
  • 原文地址:https://www.cnblogs.com/giggle/p/5572118.html
Copyright © 2011-2022 走看看