理解前端模块概念: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)流从流读出数据( ...
随机推荐
- Zookeeper什么,它可以做什么?看了这篇就懂了
前言 什么是ZooKeeper,你真的了解它吗.我们一起来看看吧~ 什么是 ZooKeeper ZooKeeper 是 Apache 的一个顶级项目,为分布式应用提供高效.高可用的分布式协调服务,提供 ...
- SQL中隔行编号的操作
一般在sql中进行排序编号的时候都是: row_number() over(order by xxx) 但是有时候某些行不想让他们参与排序,这时候可以: row_number() over(order ...
- 【STL 源码剖析】浅谈 STL 迭代器与 traits 编程技法
大家好,我是小贺. 点赞再看,养成习惯 文章每周持续更新,可以微信搜索「herongwei」第一时间阅读和催更,本文 GitHub : https://github.com/rongweihe/Mor ...
- JavaDailyReports10_10
1.4.2 键盘事件的处理 KeyListener 接口实现了处理键盘事件 KeyEvent 对象描述键盘事件的相关信息. KeyListener 接口有三个方法:KeyPressed K ...
- SpringBoot异常处理(二)
参数校验机制 JSR-303 Hibernate 参数接收方式: URL路径中的参数 {id} (@PathVariable(name="id") int-whatever) UR ...
- 这篇文章告诉你MYSQLB+树具体索引数据组织明细内容
面试题:InnoDB中一棵B+树能存多少行数据? 一.InnoDB 一棵 B+ 树可以存放多少行数据? InnoDB 一棵 B+ 树可以存放多少行数据? 这个问题的简单回答是:约 2 千万. 为什 ...
- 软件工程与UML代码互改
这个作业属于哪个课程https://edu.cnblogs.com/campus/fzzcxy/2018SE1/ 这个作业的要求在哪里https://edu.cnblogs.com/campus/fz ...
- [Abp]Abp 新手入门随记
项目结构说明 *.Application 应用服务实现 *.Application.Contracts 包含DTO及应用服务接口 *.DbMigrator 数据迁移项目 开发和生产环境迁移数据库架构和 ...
- python+sklearn+kaggle机器学习
python+sklearn+kaggle机器学习 系列教程 0.kaggle 1. 初级线性回归模型机器学习过程 a. 提取数据 b.数据预处理 c.训练模型 d.根据数据预测 e.验证 今天是10 ...
- SpringBoot 集成Shiro之使用Redis缓存授权认证信息
因为用户认证与授权需要从数据库中查询并验证信息,但是对于权限很少改变的情况,这样不断从数据库中查询角色验证权限,对整个系统的开销很大,对数据库压力也随之增大.因此可以将用户认证和授权信息都缓存起来,第 ...