es6 Node加载
Node加载
概述
Node 对 ES6模块的处理比较麻烦,因为它有自己的 CommonJS模块格式,与 ES6模块格式是不兼容的。目前的解决方案是,将两者分开,ES6模块和 CommonJS 采用各自的加载方案。
Node 要求 ES6模块采用.mjs
后缀文件名。也就是说,只要脚本文件里面使用import
或者export
命令,那么就必须采用.mjs
后缀名。require
命令不能加载.mjs
文件,会报错,只有import
命令才可以加载.mjs
文件。反过来,.mjs
文件里面也不能使用require
命令,必须使用import
。
目前,这项功能还在试验阶段。安装 Node v8.5.0 或以上版本,要用--experimental-modules
参数才能打开该功能。
$ node --experimental-modules my-app.mjs
为了与浏览器的import
加载规则相同,Node 的.mjs
文件支持 URL 路径。
import './foo?query=1'; // 加载 ./foo 传入参数 ?query=1
上面代码中,脚本路径带有参数?query=1
,Node 会按 URL 规则解读。同一个脚本只要参数不同,就会被加载多次,并且保存成不同的缓存。由于这个原因,只要文件名中含有:
、%
、#
、?
等特殊字符,最好对这些字符进行转义。
目前,Node 的import
命令只支持加载本地模块(file:
协议),不支持加载远程模块。
如果模块名不含路径,那么import
命令会去node_modules
目录寻找这个模块。
import 'baz';
import 'abc/123';
如果模块名包含路径,那么import
命令会按照路径去寻找这个名字的脚本文件。
import 'file:///etc/config/app.json';
import './foo';
import './foo?search';
import '../bar';
import '/baz';
如果脚本文件省略了后缀名,比如import './foo'
,Node 会依次尝试四个后缀名:./foo.mjs
、./foo.js
、./foo.json
、./foo.node
。如果这些脚本文件都不存在,Node 就会去加载./foo/package.json
的main
字段指定的脚本。如果./foo/package.json
不存在或者没有main
字段,那么就会依次加载./foo/index.mjs
、./foo/index.js
、./foo/index.json
、./foo/index.node
。如果以上四个文件还是都不存在,就会抛出错误。
最后,Node 的import
命令是异步加载,这一点与浏览器的处理方法相同。
内部变量
ES6模块应该是通用的,同一个模块不用修改,就可以用在浏览器环境和服务器环境。为了达到这个目标,Node 规定 ES6模块之中不能使用 CommonJS模块的特有的一些内部变量。
首先,就是this
关键字。ES6模块之中,顶层的this
指向undefined
;CommonJS模块的顶层this
指向当前模块,这是两者的一个重大差异。
其次,以下这些顶层变量在 ES6模块之中都是不存在的。
arguments
require
module
exports
__filename
__dirname
如果你一定要使用这些变量,有一个变通方法,就是写一个 CommonJS模块输出这些变量,然后再用 ES6模块加载这个 CommonJS模块。但是这样一来,该 ES6模块就不能直接用于浏览器环境了,所以不推荐这样做。
// expose.js
module.exports = {__dirname};
// use.mjs
import expose from './expose.js';
const {__dirname} = expose;
上面代码中,expose.js
是一个 CommonJS模块,输出变量__dirname
,该变量在 ES6模块之中不存在。ES6模块加载expose.js
,就可以得到__dirname
。
ES6模块加载 CommonJS模块
CommonJS模块的输出都定义在module.exports
这个属性上面。Node 的import
命令加载 CommonJS模块,Node 会自动将module.exports
属性,当作模块的默认输出,即等同于export default xxx
。
下面是一个 CommonJS模块。
// a.js
module.exports = {
foo: 'hello',
bar: 'world'
};
// 等同于
export default {
foo: 'hello',
bar: 'world'
};
import
命令加载上面的模块,module.exports
会被视为默认输出,即import
命令实际上输入的是这样一个对象{ default: module.exports }
。
所以,一共有三种写法,可以拿到 CommonJS模块的module.exports
。
// 写法一
import baz from './a';
// baz = {foo: 'hello', bar: 'world'};
// 写法二
import {default as baz} from './a';
// baz = {foo: 'hello', bar: 'world'};
// 写法三
import * as baz from './a';
// baz = {
// get default() {return module.exports;},
// get foo() {return this.default.foo}.bind(baz),
// get bar() {return this.default.bar}.bind(baz)
// }
上面代码的第三种写法,可以通过baz.default
拿到module.exports
。foo
属性和bar
属性就是可以通过这种方法拿到了module.exports
。
下面是一些例子。
// b.js
module.exports = null;
// es.js
import foo from './b';
// foo = null;
import * as bar from './b';
// bar = { default:null };
上面代码中,es.js
采用第二种写法时,要通过bar.default
这样的写法,才能拿到module.exports
。
// c.js
module.exports = function two() {
return 2;
};
// es.js
import foo from './c';
foo(); // 2
import * as bar from './c';
bar.default(); // 2
bar(); // throws, bar is not a function
上面代码中,bar
本身是一个对象,不能当作函数调用,只能通过bar.default
调用。
CommonJS模块的输出缓存机制,在 ES6 加载方式下依然有效。
// foo.js
module.exports = 123;
setTimeout(_ => module.exports = null);
上面代码中,对于加载foo.js
的脚本,module.exports
将一直是123
,而不会变成null
。
由于 ES6模块是编译时确定输出接口,CommonJS模块是运行时确定输出接口,所以采用import
命令加载 CommonJS模块时,不允许采用下面的写法。
// 不正确
import { readfile } from 'fs';
上面的写法不正确,因为fs
是 CommonJS 格式,只有在运行时才能确定readfile
接口,而import
命令要求编译时就确定这个接口。解决方法就是改为整体输入。
// 正确的写法一
import * as express from 'express';
const app = express.default();
// 正确的写法二
import express from 'express';
const app = express();
CommonJS模块加载 ES6模块
CommonJS模块加载 ES6模块,不能使用require
命令,而要使用import()
函数。ES6模块的所有输出接口,会成为输入对象的属性。
// es.mjs
let foo = { bar: 'my-default' };
export default foo;
foo = null;
// cjs.js
const es_namespace = await import('./es');
// es_namespace = {
// get default() {
// ...
// }
// }
console.log(es_namespace.default);
// { bar:'my-default' }
上面代码中,default
接口变成了es_namespace.default
属性。另外,由于存在缓存机制,es.mjs
对foo
的重新赋值没有在模块外部反映出来。
下面是另一个例子。
// es.js
export let foo = { bar:'my-default' };
export { foo as bar };
export function f() {};
export class c {};
// cjs.js
const es_namespace = await import('./es');
// es_namespace = {
// get foo() {return foo;}
// get bar() {return foo;}
// get f() {return f;}
// get c() {return c;}
// }
es6 Node加载相关推荐
- es6 循环加载ES6模块
循环加载ES6模块 "循环加载"(circular dependency)指的是,a脚本的执行依赖b脚本,而b脚本的执行又依赖a脚本. // a.js var b = requir ...
- ES6 模块加载export 、import、export default 、import() 语法与区别,笔记总结
ES6模块加载export .import.export default .import() 语法与区别 在 ES6 之前,社区制定了一些模块加载方案,最主要的有 CommonJS 和 AMD 两种. ...
- ES6模块加载方案 CommonJS和AMD ES6和CommonJS
目录 CommonJS CommonJS和AMD的对比 ES6和CommonJS 改成ES6 exports和module.exports CommonJS 每个文件就是一个模块,有自己的作用域.在一 ...
- ES6之Module 的加载实现(2)
3.Node 加载 Node 对 ES6 模块的处理比较麻烦,因为它有自己的 CommonJS 模块格式,与 ES6 模块格式是不兼容的.目前的解决方案是,将两者分开,ES6 模块和 CommonJS ...
- 【ES6】阮一峰ES6学习之Module的加载实现
Module的加载实现 1. 浏览器加载 传统方法 加载规则 ES6 模块与 CommonJS 模块的差异 1. CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用. 2. Co ...
- thymeleaf加载不了js引用_web前端教程之js中的模块化一
web前端教程之js中的模块化一:我们知道最常见的模块化方案有CommonJS.AMD.CMD.ES6,AMD规范一般用于浏览器,异步的,因为模块加载是异步的,js解释是同步的,所以有时候导致依赖还没 ...
- “睡服”面试官系列第十一篇之module加载实现(建议收藏学习)
目录 1. 浏览器加载 1.1传统方法 1.2加载规则 2. ES6 模块与 CommonJS 模块的差异 3. Node 加载 3.1概述 3.2内部变量 4ES6 模块加载 CommonJS 模块 ...
- 21.Module 的加载实现
Module 的加载实现 Module 的加载实现 上一章介绍了模块的语法,本章介绍如何在浏览器和 Node 之中加载 ES6 模块,以及实际开发中经常遇到的一些问题(比如循环加载). 浏览器加载 传 ...
- Javascript模块加载捆绑器Browserify Webpack和SystemJS用法
Javascript模块加载捆绑器Browserify Webpack和SystemJS用法 转自 http://www.jdon.com/idea/js/javascript-module-load ...
最新文章
- 利用IPSec实现网络安全之三(身份验证和加密数据)
- 【收藏】Vue+elementUI的this.$refs.对象名.方法名的理解
- RabbitMQ学习(七)_RabbitMQ Consumer获取消息的两种方式(poll,subscribe)解析
- 常用Arthas命令
- css知识笔记(一)——基础知识、选择器、元素分类
- 作者:牛怡晗,女,就职于上海浦东发展银行昆明分行。
- 收到朋友寄来的煎饼了
- ubunt18.04LTS+vscode+anaconda3下的python+C++调试
- K8s稳居容器榜首,Docker冲顶技术热词,微服务应用热度不减,2021云原生开发者现状
- cocos2dx 3.10 网狐土豪金版PC+手机端棋牌平台搭建
- python视频教程-Python视频教程
- 淘宝现重大BUG,是程序员报复?官方回应
- matlab中appdesigner的控件简单讲解
- 初学 Click 路由器
- 显示器分辨率的英文(XGA、SXGA、UXGA、WSXGA等等来表示)
- 使用opencv-python快速读取视频——进阶版
- J9数字论:什么是Web3.0概念?
- 数据库连接中useSSL是否为true 或者 false的选择
- 【毕业设计_课程设计】基于网络爬虫的新闻采集和订阅系统的设计与实现(源码+论文)
- HTTP协议中 POST和GET的区别
热门文章
- CES神吐槽:人工智能快要“烂大街”了?
- C++ 类的深拷贝和浅拷贝完美解决
- js 学习笔记(一)
- [九度][何海涛] 旋转数组的最小数字
- Lucene6.5.0 下中文分词IKAnalyzer编译和使用
- Struts2 过滤器与拦截器
- TransE:Translating Embedding多元关系数据嵌入(知识图谱嵌入)2013 NIPS
- 安装Sarge(二) 配置基本系统
- Ansible 入门:安装 简例 playbook应用
- 2015年12月16日 Oracle语句实现有则更新无则插入