理解前端模块概念: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)流从流读出数据( ...
随机推荐
- Spring Boot使用Maven自定义打包方式
前言:本文将告诉你如何将程序Jar与与依赖Jar及配置文件分离打包,以下列举了两种不同Maven打包方式,其打包效果一致! 一.第一种Maven打包方式,将jar及resources下全部配置文件,拷 ...
- MySQL全面瓦解15:视图
概述 很多时候,我们会有一些很复杂的数据库操作,比如整合用户的行为数据,那这些数据可能包含用户的餐饮.生活日用.充值消费.交通出行.通讯物流.交通出行.医疗保健.住房物业.运动健康... 基于此,我们 ...
- 数据接口请求异常:parsererror
问题一:直接拿别人的文件放在本地打开 如下图 原因:这是提示"交叉源请求仅支持协议方案:HTTP.数据.Chrome.Chrome扩展.HTTPS." 也就是你不能用本地文件打开, ...
- 漫谈JSON Web Token(JWT)
一.背景 传统的单体应用基于cookie-session的身份验证流程一般是这样的: 用户向服务器发送账户和密码. 服务器验证账号密码成功后,相关数据(用户角色.登录时间等)都保存到当前会话中. 服务 ...
- HTML学习案例-仿慕课网网页制作(一)
概述:仿制慕课网头部导航栏和分支导航栏的外观 考察知识点: 1.消除浮动的原因:如果最上面的块级元素不清楚浮动的话就会影响下面的块级元素的布局 对subnav块使用了float,结果subnav块飞到 ...
- Elasticsearch节点下线(退役)and unassigned shards
一.节点退役当集群中个别节点出现故障预警等情况,需要进行退役工作,即让所有位于该退役节点上的分片的数据分配到其他节点上后,再将此节点关闭并从集群中移除. 1.ES提供了让某个节点上所有数据都移走的功能 ...
- [每日一题]面试官问:for in和for of 的区别和原理?
关注「松宝写代码」,精选好文,每日一题 时间永远是自己的 每分每秒也都是为自己的将来铺垫和增值 作者:saucxs | songEagle 一.前言 2020.12.23 日刚立的 flag,每日一 ...
- flask socketio 踩坑记录
在使用python3的flask-socketio+socket.io.js的时候报错 在使用python3的flask-socketio+socket.io.js的时候报错"unsuppo ...
- python学习笔记 | 顺序表的常规操作
''' @author: 人人都爱小雀斑 @time: 2020/3/11 8:46 @desc: 顺序表的相关操作 ''' class SequenceList: def __init__(self ...
- 【Linux】记一次xfs分区数据恢复
项目有一块磁盘无法挂载,而且还没有做RAID.... # mount /dev/sda /xxx 报错 mount: special device /dev/sda/ does not exist ...