理解前端模块概念: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)流从流读出数据( ...
随机推荐
- React Native Android 环境搭建
因为工作需要,最近正在学习React Native Android.温故而知新,把学习的内容记录下来巩固一下知识,也给有需要的人一些帮助. 需要说明的是,我刚接触React Native也不久,对它的 ...
- svn怎么上传文件
首先去网站下载TortoiseSVN,并安装 安装完后随便打开一个文件夹,如图,笔者在 E:\svn\ 文件下创建了一个simbo文件夹,选中并右键,出现了TortoiseSVN应用的选项,我们点 ...
- 批量修改vsphere共享存储多路径选择策略
传统方式修改存储的多路径选择策略 首先说一下传统web界面操作方式: 可以看到至少需要6次才能修改完成一个.在生产环境中一般会挂载很多FC存储,这时候就需要一个批量快捷的方式来修改. 使用Powerc ...
- 美团关于分布式ID实践方案细节
摘自https://tech.meituan.com/2019/03/07/open-source-project-leaf.html Leaf是美团基础研发平台推出的一个分布式ID生成服务,名字取自 ...
- 第二章 进程同步(二)——> 重点
2.4 进程同步 2.4.1 进程同步的基本概念 1. 两种形式的制约关系 (1)间接相互制约关系:互斥问题(往往是互斥设备)---是同步的特例 (2)直接相互制约关系:同步问题 注: 互斥问题 ...
- 风炫安全WEB安全学习第二十五节课 利用XSS键盘记录
风炫安全WEB安全学习第二十五节课 利用XSS键盘记录 XSS键盘记录 同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源.所以xyz.com下的js脚本采用a ...
- 杭电OJ2007----平方和与立方和(易错题)
Problem Description 给定一段连续的整数,求出他们中所有偶数的平方和以及所有奇数的立方和. Input 输入数据包含多组测试实例,每组测试实例包含一行,由两个整数m和n组成. Out ...
- 【剑指 Offer】10-II.青蛙跳台阶问题
题目描述 一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶.求该青蛙跳上一个 n 级的台阶总共有多少种跳法. 答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008, ...
- git的使用命令总结
git一般方法git init 本地目录生成仓库git clone +项目url地址 克隆远程仓库git status 查看状态git pull 拉取 拉取的代码在用户家目录下git push 上传g ...
- Linux复制某个目录下结构
Linux复制某个目录下结构 结合tree命令把当前目录下的文件夹路径存储到document.txt文件,然后再使用mkdir命令把document.txt文件下的目录输入创建: tree -fid ...