一、关于ECMAScript6
ECMAScript 6.0(以下简称ES6)是JavaScript 语言的新一代标准,已经在2015年6月正式发布了。它的目标,是使得JavaScript语言可以用来编写复杂的大型应用程序,成为企业级开发语言。
ES6是ES5的升级版,提供了简洁的语法和新的特性。ES6在浏览器上兼容性差一些,但是在NodeJS上可以完全兼容。因此,为了解决当下的兼容性问题,主要采用将开发用的ES6转化为ES5使其能够顺利运行在浏览器端的方案。
二、模块化机制
1.概述
Node.js采用模块化结构,按照CommonJS规范定义和使用模块。在Node中,以模块为单位划分所有功能,并且提供一个完整的模块加载机制,使得我们可以将应用程序划分为各个不同的部分,并且对这些部分进行很好的协同管理。
JavaScript是一种功能强大的面向对象语言,具有一些最快速的动态语言解释器。官方JavaScript规范定义了一些用于构建基于浏览器的应用程序的对象的API。但是,规范并没有定义一个用于对于构建更广泛的应用程序的标准库。
CommonJS API将通过定义处理许多常见应用程序需求的API来填补这一空白,最终提供与Python、Ruby和Java一样丰富的标准库。其意图是应用程序开发人员能够使用CommonJS API编写应用程序,然后在不同的JavaScript解释器和主机环境中运行该应用程序(使服务器端JavaScript应用程序的开发更加便利)。
通过将各种可重用的代码编写在各种模块中的方法,我们可以大大减少应用程序的代码量,提高应用程序开发效率以及应用程序的可读性。通过模块加载机制,我们也可以将各种第三方模块引入到我们的应用程序中。
2.模块化结构
每个文件(如example.js)就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。
如果想在多个文件分享变量,必须定义为global对象的属性(全局属性),如:
global.warning = true;
Node内部提供一个Module构建函数。所有模块都是Module的实例。每个模块内部,都有一个module对象,代表当前模块。它有以下属性:
module.id:模块的识别符,通常是带有绝对路径的模块文件名
module.filename:模块的文件名,带有绝对路径
module.loaded:返回一个布尔值,表示模块是否已经完成加载
module.parent:返回一个对象,表示调用该模块的模块
module.children:返回一个数组,表示该模块要用到的其他模块
module.paths:加载模块的可选路径(逐级往上直至根目录,每层找一次模块文件名)
module.exports:表示模块对外输出的值
为了方便,Node为每个模块提供一个exports变量,指向module.exports。这等同在每个模块头部,有一行这样的命令:var exports = module.exports;。
CommonJS规范规定,每个模块内部,module变量代表当前模块。这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。加载某个模块,其实是加载该模块的module.exports属性。
require(‘’)用于加载模块,其参数可以为模块路径,也可以为模块名(此时用到paths)。
3.核心模块
path模块提供了一些工具函数,用于处理文件与目录的路径,使用如下方法引用:
var path = require(‘path’);
path.basename():该方法返回一个参数路径的最后一部分
path.dirname():该方法返回一个path的目录名
path.extname():该方法返回path的扩展名,即从path的最后一部分中的最后一个.(点)字符到字符串结束
path.isAbsolute():该方法会判定path是否为一个绝对路径
path.join():该方法使用平台特定的分隔符把全部给定的path片段连接到一起,并规范化生成的路径
path.normalize():该方法会规范化给定的path,并解析 '..' 和 '.' 片段
path.delimiter:该属性提供平台特定的路径分隔符
querystring模块提供了一些实用函数,用于解析与格式化URL查询字符串。使用如下方法引用:
var querystring = require('querystring');
querystring.stringify(obj[, sep[, eq]]):将对象转换为查询字符串
obj是要序列化成 URL 查询字符串的对象
sep用于界定查询字符串中的键值对的子字符串。默认为 '&'
eq用于界定查询字符串中的键与值的子字符串。默认为 '='
querystring.parse(str[, sep[, eq]]):将查询字符串转换为对象
url模块提供了一些实用函数,用于 URL 处理与解析。使用如下方法引用:
var url = require('url');
url.parse():将一个url地址转换为一个对象
url.resolve():该方法会以一种Web浏览器解析超链接的方式把一个目标URL解析成相对于一个基础URL,如:
url.resolve('/one/two/three','four'); //'/one/two/four'
url.resolve('http://example.com/','/one'); //'http://example.com/one'
url.resolve('http://example.com/one', '/two'); // 'http://example.com/two'
4.npm(文档地址:https://docs.npmjs.com/)
Npm使得JS开发者能够更方便的分享和复用以及更新代码,被复用的代码被称为包或者模块,一个模块中包含了一到多个js文件。在模块中一般还会包含一个package.json的文件,该文件中包含了该模块的配置信息。
一个完整的项目,需要依赖很多个模块。一个完整的npm包含三部分:npm网站(用于预览npm管理的包)、注册机制(用于上传包,使用数据库来维护包与上传者的信息)和客户端(用于安装包)。
Node.js的模块是一种能够被发布到npm上的包。创建模块从创建package.json文件开始,package.json是模块的配置文件。可以使用npm init命令来初始化package.json文件(使用$ npm init -y命令则创建默认package.json文件)。
$ npm init
name:模块名称
version:模块版本
description:描述信息
main:指定模块入口文件
Dependencies:依赖关系
engines:指定node版本
devDependencies:环境依赖或测试依赖
optionalDependencies:可选择依赖
script:定义当前模块脚本,使用npm run来运行所定义的脚本
npm会随着Node一起被安装到本地。可以使用$ npm install npm@latest -g命令来更新npm。由于默认npm的仓库在国外,下载模块时速度很慢,可以使用$ npm install -g cnpm --registry=https://registry.npm.taobao.org安装淘宝镜像,通过$ cnpm命令来加快下载速度。
执行npm时有时候会遇到权限不足的情况,可以通过以下方式进行修正:
$ npm config get prefix
$ sudo chown -R $(whoami) $(npm config get prefix)/{lib/node_modules,bin,share}
node_modules目录用于存放第三方模块。
如果想要仅在当前模块中使用某个第三方模块,就可以使用$ npm install xxx默认安装,默认安装即是本地安装;
如果想要在命令行中使用模块,就需要进行$ npm install xxx -g全局安装。安装时,如果当前目录中没有node_modules目录,npm就会创建一个该目录。
$ npm install <package_name>安装项目依赖的模块,依赖的模块定义在package.json中。
安装模块时,默认会将所安装的模块写入到package.json的dependencies属性中($ npm install xxx --save或$ npm install xxx -S),dependencies中的依赖为产品依赖。
$ npm install xxx --save-dev会将所安装的模块写入到package.json的devDependencies 属性中,devDependencies 中的依赖为开发依赖,只在产品开发阶段才会使用到,在产品阶段无需这些依赖。
$ npm update <module_name>可全局更新依赖的模块
$ npm uninstall -g <package_name>可从node_modules中删除不需要的模块
$ npm uninstall -save -g <package_name>不仅删除node_modules中的依赖,还删除package.json中的信息
5.Babel
Babel是一种JS插件,运行在NodeJS上,它能够将ES6代码转码为ES5,以便其运行在浏览器上。全局环境下进行Babel转码。这意味着,如果项目要运行,全局环境必须有Babel,也就是说项目产生了对环境的依赖,此时需要使用$ npm install -g babel-cli全局安装Babel。
安装预设并且添加配置文件配置.babelrc,在当前项目的根目录下创建该文件:
$ npm install --save-dev babel-preset-es2015
{ “presets”: [ "es2015"]}
Babel的配置文件是.babelrc,存放在项目的根目录下。使用Babel的第一步,就是配置这个文件。该文件用来设置转码规则和插件,基本格式为{ "presets": [], "plugins": [] }。
presets字段设定转码规则,官方提供以下的规则集,可以根据需要安装:
$ npm install --save-dev babel-preset-es2015 => 转码为ES2015
$ npm install --save-dev babel-preset-latest => 转码为最新规则
$ npm install --save-dev babel-preset-env => env(不会过时的转码规则)
然后,将这些规则加入.babelrc:{ “presets”: [ "es2015"], "plugins": [] , "ignore":[] }
使用Babel转码结果输出到标准输出,如:$ babel example.js
转码结果写入一个文件,--out-file或-o参数指定输出文件,如:$ babel example.js --out-file compiled.js
整个目录转码 --out-dir 或 -d 参数指定输出目录,如:$ babel src --out-dir lib
Babel默认只转换新的JavaScript句法(syntax),而不转换新的API,比如Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等全局对象,以及一些定义在全局对象上的方法(比如Object.assign)都不会转码。举例来说,ES6在Array对象上新增了Array.from方法,Babel 就不会转码这个方法,如果想让这个方法运行,必须使用babel-polyfill,为当前环境提供一个垫片:
$ npm install --save babel-polyfill安装babel-polyfill
import 'babel-polyfill'或require('babel-polyfill')在js文件中引用并且使用babel-polyfill