一、环境搭建
(一)Node介绍
- Node也叫Node.js,由Ryan-Dahl于2009年5月在GitHub发布了第一版
- Node是一个javascript运行环境(runtime)。实际上他是对Google V8引擎进行了封装
- 官网介绍:一个搭建在ChromeJavaScript运行时上的平台,用于构建高速、可伸缩的网络程序
- Node采用的时间驱动、非阻塞I/O模型,使它既轻量又高效,并成为构建运行在分布式设备上的数据密集型实时程序的完美选择
- 目前Node在实际开发中主要作为开发基础环境存在,用于进行模块管理,编译es6代码,运行各种js脚本
(二)Ndode安装
1、下载
2、安装
Linux:先将安装包解压,然后进行环境变量的配置
windows:直接点击安装即可
(三)Node使用
1、基本使用
1)执行js脚本
$ node demo.js
2)REPL环境
在命令键入node命令,后面没有文件名,就进入一个Node.js的REPL环境(Read-eval-print-loop,"读取-求值-输出循环"),可以直接运行各种JavaScript命令
$ node
> 1+1
2
>
(四)模块化结构
1、模块化
-
Node.js采用模块化结构,按照commonJS规范定义和使用模块
-
在Node中,以模块为单位划分所有功能,并且提供一个完整的模块加载机制,使得我们可以将应用程序划分为各个不同的部分,并且对这些部分很好的协同管理
-
通过将各种可重用的代码编写在各种模块中的方法,我们可以大大的减少应用程序的代码量,提高应用程序开发效率以及应用程序的可读性
-
通过模块加载机制,我们也可以将各种第三方模块引入到我们的应用程序中
1)commonJS
-
JavaScript是一种功能强大的面向对象语言,具有一些最快速的动态语言解释器
-
官方JavaScript规范定义了一些用于构建基于浏览器应用程序的对象的API。但是,规范并没有定义一个用于构建更广泛的程序的标准库
-
commonJS API将通过定义处理许多常见应用程序需求的API来填补这一空白,最终提供与Python、Ruby和Java一样丰富的标准库。其意图是应用程序开发人员能够使用commonJS API编写应用程序,然后在不同的JavaScript解释器和主机环境中运行该程序
-
在兼容commonJS的系统中,可以使用JavaScript程序开发
服务器端JavaScript应用程序 命令行工具 图形界面应用程序 混合应用程序(如Titanium或Adobe AIR)
Node应用由模块组成,采用commonJS模块规范
2)模块作用域
每一个文件都是一个模块,有自己的作用域
在一个文件里面定义的变量,函数,类,都是私有的,对其他文件不可见
私有属性:
//example.js
var x = 5;
var addx = function(value){
return value+x
}
上面代码中,变量x和函数addx,是当前文件example.js私有的,其他文件不可见
全局属性:
如果想在多个文件分享变量,必须定义为global对象的属性、
global.warning = true
3)模块交互
commonJS规范规定,每个模块内部,module变量代表当前模块。这个变量是一个对象,它的export属性(即 module.exports)是对外的接口。
加载摸个模块,其实是加载该模块的module.exports属性
定义模块:
var x = 5;
var addX = function(value){
return value+x;
};
module.export.x = x;
module.export.addX = addX;
模块加载:
require方法用于加载模块
var example = require('./example.js')
console.log(example.x);//5
console.log(example.addX(1));//
4)模块对象
Node内部提供一个module构建函数
所有模块都是module的实例,每个模块内部都有一个module对象,代表当前模块
它有以下属性:
module.id 模块的识别符,通常是带有对对路径的模块文件名
module.filename 模块的文件名,带有绝对路径
module.loaded 返回一个布尔值,表示模块是否已经加载完成
module.parent 返回一个对象,表示调用该模块的模块
module.children 返回一个数组,表示该模块要用到的其他模块
module.exports 表示模块对外输出的值
5)exports变量
为了方便,Node为每个模块提供一个export变量,指向module.exports
这等同于在每个模块头部,有这样一行命令:
var export = module.exports
(五)核心模块
1)path模块:
path模块提供看一些工具函数,用于处理文件与目录的路径,使用方法如下:
var path = require('path');
path.basename() 该方法返回参数路径的最后一个部分
path.dirname() 该方法返回一个path的目录名
path.extname() 该方法返回path的扩展名,即从path的最后一部分中的最后一个。(句号)字符到字符串结束
path.isAbsolute() 该方法判定path是否为一个绝对路径
path.join() 该方法使用平台特定的分隔符把全部给定的path片段连接到一起,并规范生成的路径
path.nomalize() 该方法会规范化给定的path,并解析'..'和'.'片段
path.delimiter 该属性提供平台特定的路径分隔符
2)querystring模块:
querystring模块提供了一些使用函数,用于解析与格式化URL查询字符串。使用如下方法引用:
var querystring = require('querystring')
querystring.stringify(obj[,sep[,eq]]) 将对象转换为查询字符串
obj 要序列化成URL查询字符串的对象
sep 用于界定查询字符串中的键值对的子字符串。默认为'&'
eq 用于界定查询字符串中的键与值的子字符串。默认为'='
querystring.parse(str[,sep[,eq]]) 将查询字符串转为对象
3)url模块:
提供了一些实用函数,用于URL处理与解析。可以通过以下方式使用:
var url = require('url')
url.parse() 将一个url地址转换为一个对象
url.resolve() 该方法会以一种web浏览器解释超链接的方式吧一个目标URL解析成相对于一个基础url
url.resolve('/one/two/three/','four');//'/one/two/four'
url.reolve('http://example.com/','one'); //'http://example.com/one'
url.resolve('http://example.com/one','/two'); //'http://example.com/two' (替换最后一个)
(六)npm
1)简介:
- npm是js开发者能够更方便的分享和复用以及更新代码,被复用的代码成为包或者模块,一个模块中包含了一个或多个js文件。
- 在模块中一般还会包含一个package.json文件,该文件中包含了该模块的配置信息。一个完整的项目需要依赖多个模块
- 一个完整的npm包含三个部分
- npm网站 --- 用于预览npm管理的包
- 注册机制 --- 用于上传包,使用数据库来维护包与上传者的信息
- 客户端 --- 用于安装包
2)创建一个模块:
Node.js的模块是一种能够被发布到npm上的包
创建模块从创建package.json文件开始,package.json是模块的配置文件
可以使用npm.init命令来初始化package.json文件
$npm init
name:模块名称
version:模块版本
description:描述信息
main:指定模块入口文件
Dependencies:依赖关系
devDependencies:环境依赖或测试依赖
engines:指定node版本
optionalDependencies:可选择依赖
script:定义当前模块脚本,使用npm run 来运行所定义的脚本
使用-y参数创建默认package.json文件
$ npm init -y
3)安装npm:
npm 会随着Node一起被安装到本地,可以使用以下命令来更新npm:
$ npm install npm@latest -g
安装淘宝镜像:
由于默认的npm仓库在国外,下载起来很慢,可以使用淘宝镜像来加快下载速度
$ npm install -g cnpm --register=https://register.npm.taobao.org
Registry注册中心:
官方:https://registry.npmjs.org
淘宝:https://registry.npm.taobao.org
私有:http://localIP:port
修改npm权限:
执行npm的时候有时候会遇到权限不足的情况,可以通过以下方式进行修正:
$ npm config get prefix
$ sudo chown -R $(whoami) $(npm config get prefix)/{lib/node_modules,bin,share}
4)模块安装:
如果想要仅在当前模块中使用某个第三方模块,就可以使用npm install的默认安装,默认安装即是本地安装;
如果想在命令行中使用模块,就需要进行全局安装。
安装时,如果当前目录中没有node_modules目录,npm就会创建一个该目录
$ npm install <package_name>
$ npm install
安装所有项目依赖的模块,依赖的模块定义在package.json中
$ npm install
安装模块时,默认会将所安装的模块写入到package.json中的dependencies属性,通过添加一些参数改变这个特性
-S, --save
-D, --save-dev:Package will appear in your devDependencies
-O, --save-optional:Package will appear in your optionalDependencies
--no--save:Prevents saving to dependencies
-E, --Save-exact:saved dependencies will be configured with an exact version rather than using npm's default semver range operator
5)模块更新:
全局更新依赖的模块
$ npm update <modules_name>
6)模块删除:
从node_modules删除不需要的模块
$ npm uninstall -g <package_name>
不仅删除node_modules中的依赖,还需要删除package.json中的信息,可以使用--save参数
$ npm uninstall --save -g <package_name>
(七)Babel
1、命令行转码babel-cli
全局环境下进行babel转码。这意味着,如果项目要运行,全局环境必须有babel,也就是说项目产生了对环境的依赖
1)安装
$ npm install --globel babel-cli
2)安装预设并且添加配置文件配置.babelrc
在当前项目的根目录下创建该文件
$ npm install --save-dev babel-preset-es2015
{"presets":["es2015"]}
2)使用
转码结果输出到标准输出
$ babel example.js
转码结果写入一个文件,--out-file或-o参数指定输出文件
$ babel example.js --out-file compiled.js
整个目录转码--out-dir或-d参数指定输出目录
$ babel src --out-dir lib
2、配置文件
babel的配置文件是.babelrc,存放在项目的根目录下
使用babel的第一步,就是配置这个文件。该文件用来设置转码规则和插件,基本格式如下:
{"presets":[],"plugins":[]}
1)preset字段设定转码规则,官方提供一下的规则集,你可以根据需要安装
ES2015转码规则
$ npm install --save-dev babel-preset-es2015 =>es2015
最新转码规则
$ npm install --save-dev babel-preset-latest =>latest
不会过时的转码规则
$ npm install --save-dev babel-preset-nev =>env
2)然后,将这些规则加入.babelrc
{"presets":["es2015"],"plugins":[],"ignore":[]}
3、将babel-cli安装到项目中
1)安装babel-cli及预设
$ npm install --save-dev babel-cli
$ npm install --save-dev babel-preset-env
2)配置文件.babelrc
$ vim.babelrc
{"preset":["env"]}
3)在package.json中添加脚本
{
//...
"script":{"build":"babel src -d lib"}
}
4)运行脚本,执行转码操作
$ npm run build
(八)babel-polyfill
babel默认只转换新的JavaScript语法(syntax),而不转换新的API
比如Iterator,Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等全局对象
以及一些定义在全局对象上的方法(Object.assign)都不会转码
举例来说:
ES6在Array对象上新增了Array.from方法,babel就不会转码这个方法
如果想让这个方法运行,必须使用babel-polyfill,为当前环境提供一个垫片
1、安装
$ npm install -save babel-polyfill
2、在js文件中引用并且使用
import "babel-polyfill";//或者require("babel-polufill")
第二章 基础知识
一、let命令
1、基本用法
ES6新增了let命令,用来声明变量。用法类似于var,但是也存在新特性:
1)let所声明的变量,只在let命令所在的代码块有效。适用于for循环
{let a = 10;var b = 1;}
//a a is not defined
//b 1
2)不存在变量提升
console.log{bar}
let bar = 2;
//报错RederenceRrror:bar is not defined
3)暂时性死区
在代码块内,使用let命令变量之前,该变量都是不可用的
var tmp = 123;
if(true){
tmp = 'abc'; //ReferenceError
let tmp;
}
4)不允许重复声明
function(){let a = 10; let a = 1;} //报错
2、块级作用域
let实际上位JavaScript新增的块级作用域。
外层作用域无法读取内层作用域的变量,内层作用域可以定义外层作用域的同名变量
let foo = 1;
{
let foo = 2;//定义同名变量
let bar = "one";
}
console.log{foo};//1
console.log(bar);//报错
块级作用域的出现,实际上使得广泛应用的立即执行函数表达式(IIFE)不再必要了
二、const命令
1、基本用法
const声明一个只读的变量。一旦声明,常量的值就不能改变
const PI = 3.1415;
PI = 3;//TypeRrror:Assignment to constant variable
1)const声明的变量不得改变值,这意味着,const一旦声明,就必须立即初始化,不能留到以后赋值
const foo; //SyntaxErroe:Missing initializer in const declaration
2)块级作用域
只在声明所在的块级作用域内有效
3)暂时性死区
在代码块内,使用let命令声明变量之前,该变量是不可用
if(true){
console.log(MAX);//ReferenceError const MAX = 5;
}
4)不允许重复声明
var message = 'hello'
let age = 25;
//以下两行都会报错
const message = 'goodbye'
const age = 30
三、解构赋值
1、解构
ES6允许按照一定模式,从数组和对象中取值,对变量进行赋值,这被称为解构(Destructing)
例如:let [a,b,c] = [1,2,3]
本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值
如果解构不成功,变量的值就等于undefined。另一种情况是不完全解构,即等号左边的模式只匹配一部分等号右边的数组。
这种情况下,解构依然成功
2、数组的解构赋值
let [a,b,c] = [1,2,3]
1)不完全解构:
let [a,[b],d] = [1,[2,3],4]; //a=1;b=2;d=4
2)集合解构:
let[head,...tail] = [1,2,3,4]; //head=1;tail=[2,3,4]
3)默认值(当匹配值严格等于undefined时,默认值生效)
let [x,y='b'] = ['a']; //x = 'a' ,y = 'b'
4)默认值也可以为函数
function f(){console.log('aaa');}
let [x=f()] =[1]
3、对象的解构赋值
1)对象的属性没有次序,变量必须与属性同名,才能取到正确的值
let {foo,bar} = {foo:'aaa',bar:'bbb'}; //foo='aaa';bar='bbb'
2)如果变量名与属性名不一致,必须写成下面这样
var {foo:baz} = {foo:'aaa',bar:'bbb'}; //baz='aaa'
3)这实际上说明,对象的解构赋值是下面形式的简写
let {foo:foo,bar:bar} = {foo:'aaa',bar:'bbb'}
4)嵌套解构:
let obj = {p:['Hello',{y:'World'}]}
let {p:[x,{y}]} = obj; //x='Hello'; y='World'
5)默认值(默认值生效的条件是:对象的属性值严格等于undefined)
var {x:y=3} = {}; //y=3
4、字符串的解构赋值
1)解构时,字符串被转换成了一个类似数组的对象
const [a,b,c,d,e] = 'hello'; //a=h;b=e;c=l;d=l;e=o
2)也可以对数组的属性解构
let {length:len} = 'hello'; //len =5
5、数值和布尔值的解构赋值
解构时,如果等号右边是数值和布尔值,则会先转为对象
let {toString:s} = 123; //s === Number.prototype.toString true
let {toString:s} = true; //s === Boolean.prototype.toString true
6、函数参数的解构赋值
1)基本语法
function add([x,y]){return x+y;}
add([1,2])
2)默认值
function move({x=0,y=0}){
return [x,y]
}
move({x:3,y:8});//[3,8]
move({x:3}); //[3,0]
move({}); //[0,0]
move(); //[0,0]
7、常见用途
1)交换变量的值
let x = 1;
let y = 2;
[x,y] = [y,x]
2)从函数返回多个值
function example(){
return [1,2,3]
}
let [a,b,c] = example();
3)函数参数的定义
function f([x,y,z]){...}
f([1,2,3])
4)提取json数据
let jsonData = {id:42,status:'OK',data:[867,5309]};
let {id,status,data:number} = jsonData;
5)输入模块的指定方法
const {SourceMapConsumer,SourceNode} = require("source-map")
6)函数参数的默认值
jQuery.ajax = function(url,{
async = true,
cache = true,
global = true,
beforeSend = function(){},
complete = function(){},
// ...more config
}){// ...do stuff}
指定参数的默认值,就避免了在函数体内部在写var foo = config.foo||'default foo';
这样的语句
7)遍历map结构
var map = new Map();
map.set('first','hello');
map.set('second','world')l
for(let[key,value] of map){
console.log(key + "is" +value)
}
第三章 对象、函数、数组的扩展
学习目标:
- 属性简写方式
- 方法简写方式
- object方法的扩展
- 函数默认值
- 箭头函数
- 扩展运算符
- Array.from()
- Array.of()
- 数组实例的find(),findIndex()
- 数组的实例fill()
- 数组实例的entries(),keys(),values()
- 数组实例的includes()
一、对象扩展
1、属性简写
ES6允许直接写入变量和函数,作为对象的属性和方法。这时,属性名为变量名,数值型为变量值
var foo = 'bar';
var baz = {foo}
=>
var baz = {foo:foo}
2、方法简写
var o = {method(){return "hello!";}};
=>
var o = {method:function(){return "hello"}}
3、属性名表达式
ES6允许字面量定义对象时,可以把表达式放在方括号内
let propKey = 'foo';
let obj = {[propKey]:true,['a'+'bc']:123}
4、方法的的name属性
函数的name属性,返回函数名
const person = {sayName(){console.log('hello!');}};
person.sayName.name; //"sayName"
5、Object(value1,value2)
同值相等,与===类似,不同之处在于:+0不等于-0;NAN等于自身
Object.is('foo','foo');//true
Object.is({},{}); //false
二、函数的扩展
1、函数参数的默认值
ES6允许为函数的参数设置默认值,即直接写在参数定义的后面
function log(x,y='World'){
console.log(x,y)
}
通常情况下,定义了默认值的参数,应该是函数的尾参数
函数的length属性,将返回没有指定默认值的参数个数
2、与解构赋值默认值结合使用
参数默认值可以与解构赋值的默认值结合起来使用
function foo({x,y=5}){
console.log(x,y)
}
foo({});//undefined 5
foo({x:1}); //1 5
foo({x:1,y:2}); //1 2
3、rest参数
ES6引入rest参数(形式为“...变量名”),用于获取函数的多余参数,这样就不需要使用arguments对象了
rest参数搭配的变量是一个数组,改变量将多余的参数放入数组中
function add(...values){
let sum = 0;
for(var val of values){
sum += val
}
return sum
}
add(2,3,5); //10
4、箭头函数
ES6允许使用“箭头”(=>)定义函数
1)基本用法:
var f = v => v;
等价于
var f = function(v){
return v;
}
如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分
如果箭头函数的代码块部分多于一条语句,就要使用大括号将他们括起来,并且使用return语句返回
2)this
箭头函数里面没有自己的this,而是引用外层的this
//ES6
function foo(){
setTimeout(()=>{
console.log('id:',this.id)
},1000)
}
//ES5
function foo(){
var _this = this;
setTimeout(function(){
console.log('id:',_this.id);
},1000)
}
不能作为构造函数,没有内部属性arguments
5、扩展运算符
扩展运算符(spread)是三个点(...)。它好比rest参数的逆运算,讲一个数组转为用逗号分隔的参数序列
console.log(...[1,2,3]); //1,2,3
1)函数的调用
function add(x,y){
return x+y
}
add(...[1,3]);
Math.max(...[14,3,77]);
2)将字符串转为数组
[...'hello'] //['h','e','l','l','o']