理解前端模块概念:CommonJs与ES6Module
前言
JavaScript里的模块
- 需要手动维护JavaScript的加载顺序。因为通常script之间会有很多依赖关系,但这种关系都是隐式的,除非一个个去查看注释(如果没有注释,那就...),否则很难指明谁依赖谁。
- 命名冲突。所有script文件所定义的所有内容都由全局作用域共享。一个人开发还好,碰上多人协作开发,那就是灾害。
- 如果script数量太多,这也会影响页面加载。因为script标签都需要向服务器请求资源,过多的请求会严重降低渲染的速度。
何为模块
- 模块自动运行在严格模式下。
- 在模块的顶层作用域创建的变量,不会被自动添加在共享的全局作用域中,它们之后在各自的模块顶层作用域下生存。
- 通过导入导出的语句,可以非常清晰的指明模块的依赖关系。
模块的发展
CommonJs
- require函数,用于导入;
- module.exports变量,用于导出;
模块
// foo.js
var name = 'foo'; // bar.js
var name = 'bar';
require('./foo.js');
console.log(name); // bar
导出
module.exports = {
name: 'foo'
}
var module = {};
// ...
module.exports = {};
exports.name = 'foo'
var module = {
exports: {}
}
var exports = module.exports;
exports = {
name: 'foo'
}
导入
// foo.js
module.exports = {
sayname: function () {
console.log('foo');
}
}; // bar.js
var sayname = require('./foo.js').sayname;
sayname(); // foo
- 模块是第一次被require加载。这时会首先执行该模块,然后导出内容。
- 模块是曾经被require加载过。这时会直接导出执行得到的结果。
// foo.js
console.log('running foo.js')
exports.name = 'foo'; // bar.js
var firstname = require('./foo').name;
console.log('firstname:', firstname); var lastname = require('./foo').name;
console.log('lastname:', lastname);
running foo.js
fistname:foo lastname:foo
var path = ['foo.js', 'bar.js'];
path.forEach(name => {
require('./' + name);
})
ES6Module
模块
// foo.js
export default {
sayname: function () {
console.log('foo');
}
}; // bar.js
import foo from './foo.js'
foo.sayname(); // foo
- 命名导出
- 默认导出
// 1
export const name = 'foo'; // 2
const name = 'foo';
export { name }
const name = 'foo';
export { name as nickname }
export default {
name: 'foo'
}
导入
// foo.js
export const name = 'foo';
// bar.js
import { name } from './foo'
console.log(name)
// foo.js
export const name = 'foo';
// bar.js
import { name as nickname } from './foo'
console.log(nickname) // 也可以通过整体导入的方法
import * as name from './foo'
console.log(name.name)
// foo.js
export default {
name: 'foo'
} // bar
import name from './foo'
console.log(name.name)
CommonJs与ES6Module的区别
对模块依赖的处理区别
- 动态:模块依赖关系的建立是发生在代码运行阶段;
- 静态:模块依赖关系的建立是发生在代码编译阶段;
导入模块值的区别
// foo
var count = 0;
module.exports = {
count: count,
add: function (a, b) {
count++;
return a+b;
}
} // bar
var count = require('./foo').count;
var add = require('./foo').add; console.log(count); // 0
add(2,3);
console.log(count); // 0 count += 1;
console.log(count); // 1(拷贝值可以更改)
// foo
let count = 0;
const add = function (a,b) {
count++;
return a+b;
}
export { count, add } // bar
import { count, add } from './foo';
console.log(count); // 0
add(2,3);
console.log(count); // 1(实时反映foo中count的值) count++; // 报错 count is read-only
循环依赖的区别
// foo
const bar = require('./bar')
console.log('来自bar:', bar);
module.exports = 'foo'; // bar
const foo = require('./foo');
console.log('来自foo:', foo);
module.exports = 'bar; // index
require('./foo')
来自foo:()
来自bar:bar
- index文件中引入了foo,此时开始执行foo中的代码;
- foo第一句导入了bar,这是foo不会继续向下执行,而是进入了bar的内部。
- 在bar中又引入了foo,这里产生了循环依赖。但并不会再次执行foo,而是直接导出返回值,也就是module.exports。但由于foo未执行完,导出值是默认的空对象,因此当bar执行到console.log时,打印出来的是空对象。
- bar执行完毕,foo继续向下执行直到流程结束。
// foo
import bar from './bar';
console.log('来自bar:', bar);
export default 'foo' // bar
import foo from './foo'
console.log('来自foo:', foo);
export default 'bar' // index
import foo from './foo'
来自foo: undefined
来自bar:bar
结尾
作者:zhangwinwin来源:github
理解前端模块概念:CommonJs与ES6Module的更多相关文章
- 转:深入理解JavaScript闭包概念
闭包向来给包括JavaScript程序员在内的程序员以神秘,高深的感觉,事实上,闭包的概念在函数式编程语言中算不上是难以理解的知识.如果对作用域,函数为独立的对象这样的基本概念理解较好的话,理解闭包的 ...
- 前端模块与CMS结合
前端模块与CMS结合 在<FIS官方技术群>经常看到一些讨论,这次是 前端组件化与CMS的相关讨论,主要观点来自群里 漂流瓶(张云龙前辈). CMS是运营人员直接操作,我们往往需求各种各样 ...
- webpack前言:前端模块系统的演进
前端开发和其他开发工作的主要区别,首先是前端是基于多语言.多层次的编码和组织工作,其次前端产品的交付是基于浏览器,这些资源是通过增量加载的方式运行到浏览器端,如何在开发环境组织好这些碎片化的代码和资源 ...
- 前端模块化(CommonJs,AMD和CMD)
前端模块规范有三种:CommonJs,AMD和CMD. CommonJs用在服务器端,AMD和CMD用在浏览器环境 AMD 是 RequireJS 在推广过程中对模块定义的规范化产出. CMD 是 S ...
- 后端技术杂谈11:十分钟理解Kubernetes核心概念
本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 本文转自 https://github.com/h2pl/Java-Tutorial 喜欢的 ...
- 理解 Keystone 核心概念 - 每天5分钟玩转 OpenStack(18)
作为 OpenStack 的基础支持服务,Keystone 做下面这几件事情: 管理用户及其权限 维护 OpenStack Services 的 Endpoint Authentication(认证) ...
- (转)深入理解JavaScript 模块模式
深入理解JavaScript 模块模式 (原文)http://www.cnblogs.com/starweb/archive/2013/02/17/2914023.html 英文:http://www ...
- 深入理解JavaScript 模块模式
http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html 模块模式是JavaScript一种常用的编码模式.这是一般的 ...
- Java IO 理解流的概念
Java IO 理解流的概念 @author ixenos 在理解流时首先理解以下概念 1.流的来源和去向一般在构造器指出 2.方法中的形参一般是将流输出到某个位置,读取(INPUT)流从流读出数据( ...
随机推荐
- Qt学习笔记-Qt-4.8.6+phonon+mplayer
首先,用phonon播放音乐时,可以使用mplayer.首先,你的设备上需要安装一个mplayer并测试能用. 然后安装后端播放插件. 我用的是网上找的phonon-mplayer. 按照网上的方法, ...
- HttpMessageConverter那回事
相信使用过Spring的开发人员都用过@RequestBody.@ResponseBody注解,可以直接将输入解析成Json.将输出解析成Json,但HTTP 请求和响应是基于文本的,意味着浏览器和服 ...
- CentOS7 普通用户绕过root登录
正常环境中我们的服务器都会使用一个普通用户跳转到root进行操作,如果root用户的密码不记得只知道普通用户密码,设备又不方便进行开关机破密码时,我们就可以用到以下方法登陆设备. pkexec : ...
- js--实现限制input输入框数字输入,实现每四位一个空格效果(银行卡号,手机号等)
前言 工作学习中经常能遇到输入框限制输入数字,并且每四位一空格的情况,比如表单中银行卡号,手机号等输入框的限制,这里介绍一下使用js具体的实现方法.不需要引用第三方ui库. 正文 1.input标签的 ...
- Django(投票程序)
Django是一个web框架,python编写的. MTV模式 Django的MTV模式本质上和MVC是一样的,也是为了各组件间保持松耦合关系,只是定义上有些许不同 -M代表模型(Model ):负责 ...
- 【MyBatis】MyBatis 注解开发
MyBatis 注解开发 文章源码 环境搭建 Mybatis 也可以使用注解开发方式,这样就可以减少编写 Mapper 映射文件. 常用注解说明: @Insert 实现新增 @Update 实现更新 ...
- Linux学习笔记 | docker基本命令
Docker的三大核心概念:镜像.容器.仓库 镜像:类似虚拟机的镜像.用俗话说就是安装文件. 容器:类似一个轻量级的沙箱,容器是从镜像创建应用运行实例,可以将其启动.开始.停止.删除.而这些容器都是相 ...
- /usr/bin/ld: cannot find -lc
yum install glibc-static [root@test chkrootkit-0.50]# make sensecc -static -o strings-static strings ...
- disfunc绕过
绕过DisFunc的常见小技巧 解析webshell命令不能执行时的三大情况 一是 php.ini 中用 disable_functions 指示器禁用了 system().exec() 等等这类命令 ...
- jQuery库 之 jquery slimscroll插件使用
1.引入jQuery插件 <script type="text/javascript" src="jquery.min.js"></scrip ...