export,,export default,import || export,module.exports,require

参考地址 https://www.jianshu.com/p/be2d4eab3878

module.exports

Node应用由模块组成,采用CommonJS模块规范。根据这个规范,每个文件就是一个模块,有自己的作用域。在这些文件里面定义的变量、函数、类,都是私有的,对外不可见,因此规避掉了作用域污染。

根据CommonJS规定,每个模块内部,module变量代表当前模块,这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。加载某个模块,其实就是加载该模块的exports属性。

举例:通过module.exports输出变量 age 和 sayHelloTo 函数。

//./MyModule.js
    var age = 7; 
    var sayHelloTo= function (name) { 
        return "hello " + name;
    }; 
    module.exports.age = age; 
    module.exports.sayHelloTo=sayHelloTo;

require:用于加载模块

var temp = require('./MyModule.js');  
//这里也可以使用 import temp from './MyModule.js'
console.log(temp.age); // 7 
console.log(temp.sayHelloTo("Steve")); // hello 

exports 与 module.exports

为了方便,node为每个模块提供了一个exports变量,指向module.exports。这等同于在每个模块头部,有这么一行代码:

var exports = module.exports;

因此,我们可以直接在exports对象上添加方法(等同于在 module.exports 添加一样)

//./MyModule.js
    var age = 7; 
    var sayHelloTo= function (name) { 
        return "hello " + name;
    }; 
    exports.age = age;  //等效于:  module.exports.age = age;
    exports.sayHelloTo=sayHelloTo;  //等效于: module.exports.sayHelloTo=sayHelloTo;

P.S.不能直接将exports指向一个值,这会切断 exports 与 module.exports 的联系(但是可以用module.exports来指向一个值)

//./MyModule.js
    var age = 7; 
    var sayHelloTo= function (name) { 
        return "hello " + name;
    }; 
    exports = age;  //不要这么干。这么做会切断exports与module.exports的联系, require该文件会得到一个空对象
    module.exports = age; //这样写没有问题,require该文件会得到一个值7

不同于CommonJS,ES6使用 export 和 import 来导入、导出模块

用 export 导出的模块,需要用 import 来进行导入,而不能用 require。
P.S.:export 命令规定的是对外的接口,必须与模块内部的变量建立一一对应的关系

const utils = {
    showSth : function(){
        console.log("showSth");
    },
    saySth : function(){
        console.log("saySth");
    }
}
//导出的3种方式
// 方式1,这种方式在引用的时候需要这样: import {m} from './utils.js';
export var m = utils; 
// 方式2,用大括号来导出变量,如果导出的变量有多个,则{变量1,变量2,变量3...,变量N}。
//这种方式在引用的时候需要这样: import {utils} from './utils.js';
export {utils}; 
// 方式3,这种方式在引用的时候需要这样: import {myUtils} from './utils.js';
//在引用的地方,也可以直接指定别名,如:import {myUtils as utils} from './utils.js';
export {utils as myUtils}; 

export 和 export default

  1. export 和export default 均可用于导出(常量 | 函数 | 文件 | 模块)等。
  2. 可以在其他文件中通过 import+(常量 | 函数 | 文件 | 模块)名的方式,将其导入,以便能够进行使用。
  3. 在一个文件或者模块中,export、import 可以有多个,但 export default 仅有一个。
const utils = {
    showSth : function(){
        console.log("showSth");
    },
    saySth : function(){
        console.log("saySth");
    }
}
const name = "my name is Artech";
export {name}; //命名导出
export {utils};

//对于命名方式导出的,在导入的时候必须使用相应对象的相同名称
//引用的时候:
import {utils,name as myName} from './utils.js';
  1. 通过 export 方式导出,在导入时要用花括号{ };而通过 export default 方式导出的,则不需要:
//如通过 export default 导出
  export default utils;  
//则在使用的时候不用加花括号,且导入时的名字可以自定义,如:
  import myUtils from './utils.js';  //对于默认方式导出的,则导入的时候,名称可以随便取

//默认导出:不能使用 let,var 或 const 作为默认导出

import *

将一个js文件中定义的方法,模块,对象等,全部导出,一般结合别名使用,如:

//myModule.js
   export const fun1 = ()=>{}
   export const objInfo = {...};
//demo.js:引用mymODULE。JS
    import * as myAlias from './myModule';
    //fun1()和objInfo都是定义在myModule中的方法和对象
    myAlias.fun1();
    myAlias.objInfo;

补充:

1. 如果用export default导出,然后用import * 引入
//myModule.js
   export default {
    fun1: ()=>{},
    objInfo: {
      aaa: 'sss1'
    },
  }
//demo.js:引用myModule.js
    import * as myAlias from './myModule';
    //fun1()和objInfo都是定义在myModule中的default的方法和对象
    myAlias.default.fun1();
    myAlias.default.objInfo;

本质上,export default就是输出一个叫做default的变量或方法,然后系统允许你为它取任意名字。所以,下面的写法是有效的。

//demo.js:引用myModule.js
    import { default as myAlias } from './myModule';
    myAlias.fun1();
    myAlias.objInfo;

正是因为export default命令其实只是输出一个叫做default的变量,所以它后面不能跟变量声明语句

// 正确
export var a = 1;

// 正确
var a = 1;
export default a;

// 错误
export default var a = 1;

上面代码中,export default a的含义是将变量a的值赋给变量default。所以,最后一种写法会报错。

同样地,因为export default命令的本质是将后面的值,赋给default变量,所以可以直接将一个值写在export default之后。

// 正确
export default 42;

// 报错
export 42;

2. export语句输出的接口,与其对应的值是动态绑定关系,即通过该接口,可以取到模块内部实时的值。
//myModule.js
export var foo = 'bar';
setTimeout(() => foo = 'baz', 500);
//demo.js:引用myModule.js
  import * as myAlias from './myModule';
  console.log(myAlias.foo); //bar
  setTimeout(() => {
    console.log(myAlias.foo); //baz
  },1000);

这一点与 CommonJS 规范完全不同。CommonJS 模块输出的是值的缓存,不存在动态更新


3. export 和 import 命令可以出现在模块的任何位置,只要处于模块顶层就可以。如果处于块级作用域内,就会报错,这是因为处于条件代码块之中,就没法做静态优化了,违背了 ES6 模块的设计初衷。
function foo() {
  export default 'bar' // SyntaxError
}
foo()

上面代码中,export语句放在函数之中,结果报错。


4. import命令输入的变量都是只读的,因为它的本质是输入接口。也就是说,不允许在加载模块的脚本里面,改写接口。
import {a} from './xxx.js'

a = {}; // Syntax Error : 'a' is read-only;

上面代码中,脚本加载了变量a,对其重新赋值就会报错,因为a是一个只读的接口。但是,如果a是一个对象,改写a的属性是允许的。

import {a} from './xxx.js'

a.foo = 'hello'; // 合法操作

上面代码中,a的属性可以成功改写,并且其他模块也可以读到改写后的值。不过,这种写法很难查错,建议凡是输入的变量,都当作完全只读,轻易不要改变它的属性。


5. import命令具有提升效果,会提升到整个模块的头部,首先执行。
foo();

import { foo } from 'my_module';

上面的代码不会报错,因为import的执行早于foo的调用。这种行为的本质是,import命令是编译阶段执行的,在代码运行之前。


6. 由于import是静态执行,所以不能使用表达式和变量,这些只有在运行时才能得到结果的语法结构。
// 报错
import { 'f' + 'oo' } from 'my_module';

// 报错
let module = 'my_module';
import { foo } from module;

// 报错
if (x === 1) {
  import { foo } from 'module1';
} else {
  import { foo } from 'module2';
}

上面三种写法都会报错,因为它们用到了表达式、变量和if结构。在静态分析阶段,这些语法都是没法得到值的。


7.import语句会执行所加载的模块,因此可以有下面的写法。
import 'lodash';

上面代码仅仅执行lodash模块,但是不输入任何值。
如果多次重复执行同一句import语句,那么只会执行一次,而不会执行多次。

import 'lodash';
import 'lodash';

上面代码加载了两次lodash,但是只会执行一次。

import { foo } from 'my_module';
import { bar } from 'my_module';

// 等同于
import { foo, bar } from 'my_module';

上面代码中,虽然foobar在两个语句中加载,但是它们对应的是同一个my_module实例。也就是说,import语句是 Singleton 模式。


8.目前阶段,通过 Babel 转码,CommonJS 模块的require命令和 ES6 模块的import命令,可以写在同一个模块里面,但是最好不要这样做。因为import在静态解析阶段执行,所以它是一个模块之中最早执行的。下面的代码可能不会得到预期结果。
require('core-js/modules/es6.symbol');
require('core-js/modules/es6.promise');
import React from 'React';

9. 如果想在一条import语句中,同时输入默认方法和其他接口,可以写成下面这样。
import _, { each, forEach } from 'lodash';

对应上面代码的export语句如下。

export default function (obj) {}
export function each(obj, iterator, context) { }
export function forEach () { }

10. export default也可以用来输出类。
// MyClass.js
export default class { ... }

// main.js
import MyClass from 'MyClass';
let o = new MyClass();

11. export 与 import 的复合写法

如果在一个模块之中,先输入后输出同一个模块,import语句可以与export语句写在一起。

export { foo, bar } from 'my_module';

// 可以简单理解为
import { foo, bar } from 'my_module';
export { foo, bar };

上面代码中,exportimport语句可以结合在一起,写成一行。但需要注意的是,写成一行以后,foobar实际上并没有被导入当前模块,只是相当于对外转发了这两个接口,导致当前模块不能直接使用foobar


未总结的:

模块的继承
跨模块常量

如果要使用的常量非常多,可以建一个专门的constants目录,将各种常量写在不同的文件里面,保存在该目录下。然后,将这些文件输出的常量,合并在index.js里面。

import() - 提案

importexport命令只能在模块的顶层,不能在代码块之中(比如,在if代码块之中,或在函数之中)。

这样的设计,固然有利于编译器提高效率,但也导致无法在运行时加载模块。在语法上,条件加载就不可能实现。如果import命令要取代 Node 的require方法,这就形成了一个障碍。因为require是运行时加载模块,import命令无法取代require的动态加载功能。

const path = './' + fileName;
const myModual = require(path);

上面的语句就是动态加载,require到底加载哪一个模块,只有运行时才知道。import命令做不到这一点。

因此,有一个提案,建议引入import()函数,完成动态加载。
.....

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342