简介
ES6是一个泛指,含义是 5.1 版以后的 JavaScript 的下一代标准,涵盖了 ES2015、ES2016、ES2017 等,ES6 的第一个版本,在 2015 年 6 月发布了正式名称就是《ECMAScript 2015 标准》(简称 ES2015)。
ES6在ES5的基础上拓展了很多新特性。
(1)JavaScript包含三部分:ECMAScript、DOM、BOM,其中ECMAScript是JavaScript的核心标准。ES6是ECMAScript的升级版本,也就是说JavaScript的核心部分进行了升级,在ES6中不包含DOM和BOM操作。
(2)ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现。
(3)ES6兼容性差,需要找工具来提高兼容性。常用工具有bable-cli(转码工具),可以将ES6代码在编译时转换为ES5代码。
简单对比ES5和ES6
ES5 | ES6 |
---|---|
语法比ES6稍微复杂,操作比较复杂 | 操作简单,语法简单 |
兼容性好 | 兼容性不好,需要借助转译工具 |
变量只有var | 变量有let、const |
只有全局作用域,函数作用域,无块级作用域 | 有全局、局部以及块级作用域 |
变量声明可以提升 | 变量声明不可以提升 |
变量重复赋值会覆盖前面的值 | 不能重复赋值 |
没有模块体系 | 有模块体系 |
1、模块化/工程化
Javascript一直没有模块体系,无法将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来。这对开发大型的、复杂的项目形成了巨大障碍。
在 ES6 之前,社区制定了一些模块加载方案,最主要的有 CommonJS 和 AMD 两种。前者用于服务器,后者用于浏览器。
而ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。
一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。
从 v13.2 版本开始,Node.js 已经默认打开了 ES6 模块支持。在v12的版本里面,需要在package.json配置文件中设置"type": "module",
- 简单介绍下其他模块化规范及其模块化规范产品
1、CommonJS,使用该规范的有NodeJS、Browserify,处理浏览器的。
2、AMD,使用该规范的有requireJS,处理服务器的。
3、CMD,使用该规范的有seaJS
1.1 ES6模块化*
如果学过java,可以把模块化看成是java中的导包打包的操作,使用到的关键字也很相似,例如导出模块export,导入模块import。
1.1.1 简介
ES6 模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。
ES6 模块不是对象,而是通过export命令显式指定输出的代码,再通过import命令输入。引入模块其实就是加载模块里面的方法或者变量,这个加载过程称为“编译时加载”或者静态加载,即 ES6 可以在编译时就完成模块加载,而CommonJS模块是运行时加载,ES6要比 CommonJS 模块的加载效率高。
ES6 的模块自动采用严格模式,即严格按照语法来。
1.1.2 export导出模块
1.1.2.1 介绍
如果希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量。export命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系,也就是说外部接口需要用这个接口名来引用。
例如:在src目录下创建一个testModal.js文件,文件内容如下:
let firstName = "Michael";
let lastName = "vichy";
export {firstName, lastName};
- 使用ES6的要求
首先必须在package.json配置文件添加如下内容"type": "module"
,不添加会报错,例如在终端执行如下:
在package.json配置文件中添加如下内容才能正常运行
添加后的运行结果
1.1.2.2 export的使用方式
let firstName = "Michael";
let lastName = "vichy";
//列表形式导出
export {firstName, lastName};
//重命名变量后导出,使用AS进行重命名
export {firstName as first, lastName as last};
//导出单个属性
export let a = 3;
//下面这样的形式是错误的
let b = 1;
export b; //报错
// 这里报错的地方要么改成
// export {b}; //写成列表形式
// 要么改成
// export let b = 1;
//导出一个函数
export function multiply(x,y){
return x * y;
}
//默认导出
/*注意:
一个模块只能有一个默认导出
*/
export default {} //第一个默认导出
// export default function foo(){} //第二个默认导出,报错,只能有一个默认导出。
//导出整个文件
需要特别注意的是,export命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系,不能直接导出一个值。
1.1.3 import导入模块
1.1.3.1 介绍
静态的import 语句用于导入由另一个模块导出的绑定。
使用import命令的时候,用户需要知道所要加载的变量名或函数名,否则无法加载.
而有时候这需要查文档。有时候确实有人不想查看文档去了解变量名等,懒人是促进发明创新的先锋,为了给用户提供方便,让他们不用阅读文档就能加载模块,就要用到export default命令,为模块指定默认输出。
例如:
export default function foo() {
console.log('foo');
}
其他模块加载该模块时,import命令可以为该匿名函数指定任意名字。如下:
import customName from './export-default';
customName(); // 'foo’
1.1.3.2 import的使用方式
// 导入整个模块内容
import * as person from '要导入模块的路径'
// 导入列表内的多个接口
import {firstName,lastName} from '要导入模块的路径'
// 重命名导入
import {firstName as name} from '.要导入模块的路径'
// 运行整个模块而不导入任何值
import '要导入模块的路径';
// 导入使用export default导出的模块,myDefault是给匿名函数(默认函数)任意指定的名字
import myDefault from '要导入模块的路径';
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script type="module"> import * as s1 from "../JS/test10.js"; console.log(s1); </script> </body> </html>
// test10.js文件 // 导出 export let school = "qinghua"; export function teach(){ console.log("环境加入!"); }
1.2 CJS模块化
1.2.1 介绍
CommonJS (CJS) 和 AMD 模块,都只能在运行时确定模块之间的依赖关系,以及输入输出的变量。比如,CommonJS 模块就是对象,输入时必须查找对象属性。
例如如下代码:
// CommonJS模块
let { stat, exists, readfile } = require('fs');
// 等同于如下代码块
let _fs = require('fs');
let stat = _fs.stat;
let exists = _fs.exists;
let readfile = _fs.readfile;
上面代码的实质是整体加载fs模块(即加载fs的所有方法),生成一个对象(_fs),然后再从这个对象上面读取 3 个方法。这种加载称为“运行时加载”,因为只有运行时才能得到这个对象,导致完全没办法在编译时做“静态优化”。
1.2.2 模块对象
Node内部提供一个Module构建函数。所有模块都是Module的实例。每个模块内部,都有一个module对象,代表当前模块。它有以下属性,通过module.XXX
来使用:
属性 | 说明 |
---|---|
id | 模块的识别符,通常是带有绝对路径的模块文件名 |
filename | 模块的文件名,带有绝对路径 |
loaded | 返回一个布尔值,表示模块是否已经完成加载 |
parent | 返回一个对象,表示调用该模块的模块 |
children | 返回一个数组,表示该模块要用到的其他模块 |
exports | 表示模块对外输出的值 |
1.2.3 exports导出
为了方便,Node为每个模块提供一个exports变量,指向module.exports。使用module.exports={}
或者exports.XXXX=""
来导出。
同在每个模块头部,有一行这样的命令:
let exports = module.exports;
1.2.4 require导入
require函数是nodejs提供的内置函数,用于加载指定路径的模块或者是指定名称的模块。将加载的模块进行返回,使用如下:
let path = require('指定模块路径\名称');
1.2.5 CJS导出导入的具体使用
在src
下创建testExports.js
和testRequire.js
文件,testExports.js
用来测试导出,testRequire.js
用来测试导入。
testExports.js
文件内容如下:
// 导出
module.exports = {
firstName: 'Michael',
lastName: 'vicky'
say:function(){
console.log(firstName + " " + lastName);
}
};
testRequire.js
文件内容如下:
// 导入
const { firstName, lastName, say } = require('./testExports');
console.log(firstName, lastName);
say();
执行node src/testRequire.js
命令,能正常输出结果。
1.3 使用模块化的好处
1、防止命名冲突
- JS本身是没有命名空间的,为了减少命名冲突,经常使用对象或者闭包来减少命名冲突。对象只能减少命名冲突的概率,闭包的过多使用会造成内存泄漏。模块化开发之后,在模块内任何形式的命名都不会和其他模块的命名产生冲突,有效的解决了命名冲突的问题。
2、实现代码复用
当我们想要实现某个功能的时候,如果某个模块正好有这个功能,我们就可以直接引用该模块,不必再写多余的代码,这样可以提高代码整体的效率,减少重复冗余的代码。
3、高维护性
4、解决文件之间的高度依赖
当你引入很多个JS文件的时候,很有可能会不清楚这些JS文件之间的依赖关系,从而导致加载顺序出错。使用模块化开发之后就能避免这个问题。
1.5 ES6和CommonJS模块化的区别
- ES6 模块输出的是值的引用。
ES6 模块加载的不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。ES6 模块输出的是值的引用。- CommonJS 模块输出的是一个值的拷贝。
CommonJS加载的是一个对象,即module.exports属性,该对象只有在脚本运行完才能生成。CommonJS 模块输出的是值的拷贝。- CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
验证ES6导出的是值引用,如下:
//testES6.js
let firstname = 'ren';
let lastname = 'terry';
setTimeout(() => {
firstname = 'zhao';
}, 2000);
export { firstname, lastname };
//===============另一个文件===============
//useES6.js
import { firstname, lastname } from './testES6.js'
console.log(firstname, lastname);
setTimeout(() => {
console.log(firstname, lastname);
}, 4000);
结果:
$ node src/useES6.js
ren terry
zhao terry
验证CommonJS导出的是值的拷贝,如下:
//testCommonJS.js
let firstname = 'ren';
let lastname = 'terry';
//设置任务队列,在主线程执行之后再执行,虽然这里放在导出的前面,因为导出是主线程的操作,所以其实会先进行主线程中的导出操作,之后再执行这个任务队列。并且在主线程输出值了之后,即便模块内部进行重新赋值也改变不了结果。
setTimeout(() => {
firstname = 'zhao';
}, 2000);
module.exports = {
firstname: firstname,
lastname: lastname
// 对象属性的简写方式
/* firstname,
lastname */
};
//===============另一个文件===============v
//useCommonJS.js
let { firstname, lastname } = require('./testCommonJS.js');
console.log(firstname, lastname);
setTimeout(() => {
console.log(firstname, lastname);
}, 4000)
结果:
$ node src/useCommonJS.js
ren terry
ren terry
2、包管理器
NPM 是 Node.js 标准的软件包管理器。在 2017 年 1 月时,npm 仓库中就已有超过 350000 个软件包,这使其成为世界上最大的单一语言代码仓库,并且可以确定几乎有可用于一切的软件包。它起初是作为下载和管理 Node.js 包依赖的方式,但其现在也已成为前端 JavaScript 中使用的工具。
npm工具在安装了nodejs软件
后就安装好了。所以如果没有安装nodejs软件,需要先安装nodejs软件。
中使用的工具。
NPM是Javascript开发者能够更方便的分享和复用以及更新代码的工具,被复用的代码被称为包或者模块,一个模块中包含了一到多个js文件。在模块中一般还会包含一个package.json的文件,该文件中包含了该模块的配置信息。该文件是个json文件,其配置信息如下:
name 模块名称
version 模块版本
description 描述信息
main 指定模块入口文件
type 当type值为module的时候,支持es模块化
scripts 脚本,使用’ npm run 脚本名’可以调用
dependencies 依赖关系
devDependencies 环境依赖或测试依赖常用的有三类包管理器,并且这几个包管理器可以互相替换。cnpm 是 npm 的一个替代选择,yarn 也是 npm 的一个替代选择。
通常npm的下载安装速度是很慢的,有如下几种方式可以提高下载安装速度。
-
方案一:修改npm仓库地址为淘宝仓库地址
# 修改npm下载的仓库地址 $ npm config set registry http://registry.npm.taobao.org/ # 改回原来的地址 $ npm config set registry https://registry.npmjs.org/ # 查看是否修改成功 $ npm config get registry
-
方案二:可以使用淘宝的npm镜像cnpm,cnpm的使用与npm使用非常类似。不过在使用之前要先安装cnpm。
$ npm install -g cnpm --registry=https://registry.npm.taobao.org
- 方案三:可以使用淘宝yarn工具,yarn的使用与npm使用类似。不过在使用之前要先安装yarn。
$ npm install -g yarn --registry=https://registry.npm.taobao.org
MAC下下载可能会提示错误,一般是提升权限问题,命令前加个su
修改npm权限
执行npm的时候有时会遇到权限不足的情况,可以通过以下方式进行修正。
$ npm config get prefix
$ sudo chown -R $(whoami) $(npm config get prefix)/{lib/node_modules,bin,share}
2.1 npm包管理器
通过npm可以为当前项目安装依赖模块,更新依赖模块,删除依赖模块。
- 创建一个app目录,终端进入到该app目录,使用如下命令初始化项目,会在项目根目录下会创建packge.json文件。
# 以下命令会一步一步创建项目
$ npm init
# 以下命令会快速创建项目
$ npm init -y
重新安装npm命令,使用以下命令来更新npm
npm install npm@latest -g
- 安装单个模块依赖
# 不带-g的为本地安装
$ npm install <module_name>
# 如下命令带-g是全局下载依赖
$ npm install -g <module_name>
$ npm install --global <module_name>
# 如下命令会在项目内下载依赖,并将安装记录保存在package.json的dependencies内,安装产品阶段的依赖
$ npm install -S <module_name>
$ npm install --save <module_name>
# 如下命令会在项目内下载依赖,并将安装记录保存在package.json的devDependencies内,安装生产阶段的依赖
$ npm install -D <module_name>
$ npm install --save-dev <module_name>
-
安装项目全部依赖模块
$ npm install
-
更新依赖模块
$ npm update <module_name>
-
删除依赖模块
$ npm uninstall <module_name>
全局安装,安装到全局,在任何目录下都可以使用你安装的这个插件;
项目安装,安装到当前项目的文件夹内,只能在项目目录内使用。
项目开发思想:工具全局安装,项目依赖局部安装
无论在哪个目录下执行安装代码cnpm install -g 包名,都是全局安装。
//============================================================================
A)npm install本地安装:
(1)将安装包放在 ./node_modules 下(运行 npm 命令时所在的目录),如果没有 node_modules目录,会在当前执行 npm 命令的目录下生成 node_modules 目录。
(2)可以通过 require() 来引入本地安装的包。
B)npm install -g全局安装:
(1) 将安装包放在 /usr/local 下或者你 node 的安装目录。
(2)可以直接在命令行里使用。
//============================================================================
A)npm install --save
(1)会把msbuild包安装到node_modules目录中
(2)会在package.json的dependencies属性下添加msbuild
(3)之后运行npm install命令时,会自动安装msbuild到node_modules目录中
(4)之后运行npm install --production或者注明NODE_ENV变量值为production时,会自动安装msbuild到node_modules目录中
B)npm install --save-dev
(1)会把msbuild包安装到node_modules目录中
(2)会在package.json的devDependencies属性下添加msbuild
(3)之后运行npm install命令时,会自动安装msbuild到node_modules目录中
(4)之后运行npm install --production或者注明NODE_ENV变量值为production时,不会自动安装msbuild到node_modules目录中
2.2 cnpm包管理器
使用方式和npm包管理器一致。
-
全局安装cnpm
$ npm install -g cnpm --registry=https://registry.npm.taobao.org
-
测试是否安装成功
$ cnpm -v
- 初始化项目,在项目根目录下会创建packge.json文件
# 以下命令会一步一步创建项目,会让用户输入一些项目信息,参考之前package.json里的信息 $ cnpm init # 以下命令会快速创建项目 $ cnpm init -y
-
安装单个模块依赖
$ cnpm install <module_name> # 如下命令全局下载依赖 $ cnpm install -g <module_name> $ cnpm install --global <module_name> # 如下命令会在项目内下载依赖,并将安装记录保存在package.json的dependencies内,安装生产阶段的依赖 $ cnpm install -S <module_name> $ cnpm install --save <module_name> # 如下命令会在项目内下载依赖,并将安装记录保存在package.json的devDependencies内,安装产品阶段的依赖 $ cnpm install -D <module_name> $ cnpm install --save-dev <module_name>
-
安装项目全部依赖模块
$ cnpm install
-
更新依赖模块
$ cnpm update <module_name>
-
删除依赖模块
$ cnpm uninstall <module_name>
2.3 yarn包管理器
yarn包管理器与npm类似,作用相同,命令有所不同。
-
全局安装yarn
$ npm install -g yarn --registry=https://registry.npm.taobao.org
-
测试是否安装成功
$ yarn -v
- 初始化项目,在项目根目录下会创建packge.json文件
# 以下命令会一步一步创建项目 $ yarn init # 以下命令会快速创建项目 $ yarn init -y
-
安装单个模块依赖
# 如下命令会在项目内下载依赖,并将安装记录保存在package.json的dependencies内,安装生产阶段的依赖 $ yarn add <module_name> # 如下命令会在项目内下载依赖,并将安装记录保存在package.json的devDependencies内,安装产品阶段的依赖 $ yarn add <module_name> --dev
-
安装项目全部依赖模块
$ yarn
-
更新依赖模块
$ yarn upgrade <module_name>
-
删除依赖模块
$ yarn remove <module_name>
2.4 包管理器对比
用途 | npm | cnpm | yarn |
---|---|---|---|
初始化项目 | npm init | cnpm init | yarn init |
安装项目的所有依赖 | npm install | cnpm install | yarn |
安装xxx依赖到产品阶段 | npm install xxx --save | cnpm install xxx --save | yarn add xxx |
安装xxx依赖到开发阶段 | npm install xxx --save-dev | cnpm install xxx --save-dev | yarn add xxx --dev |
移除xxx依赖 | npm uninstall xxx --save | cnpm uninstall xxx --save | yarn remove xxx |
更新项目依赖包 | npm update --save | cnpm update --save | yarn upgrade |