1.let与const
新的两种声明方式主要是弥补了var声明方式变量提升带来的负面影响。
首先let声明的变量不会提升:
//es5
console.log(a); //undefined
var a=46;
//es6
console.log(a); //报错
let a=44;
其次,let只在它所在的块级作用域中有效,如:
//es5
{
let a=4;
var b=5;
}
a //报错
b //5
更多的,他被经常使用在循环计数中
//es5
var a=[];
for(var i=0;i<5;i++){
a[i]=function(){
console.log(i)
}
}
a[3](); //5
//原因在于var声明的变量i被提升为全局变量,调用时console的i与循环结束后的i值为同一个值,此时i值为5.
//es6
var a=[];
for(let i=0;i<5;i++){
a[i]=function(){
console.log(i)
}
}
a[3](); //3,此时每个a[i]函数都被分别定义,正确输出
const主要用于声明不可更改的常量,他与let具有差不多的特性:
- const声明一个只读的常量。一旦声明,常量的值就不能改变。
- const声明的变量不得改变值,这意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值。
- const的作用域与let命令相同:只在声明所在的块级作用域内有效。
- const命令声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。
- const声明的常量,也与let一样不可重复声明。
- const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。这意味着,对于基础类型数据,const声明的变量就是数值本身,而对于引用类型的数据,变量保存的是数据的地址,只要地址不变,变量本身身可以变化的。如:
const oDe={
a:20,
b:39
}
oDe.a=89;
console.log(oDe.a);// 89,对象本身改变没问题
oDe={}; //报错,对象地址改变不行
2.模板字符串
这是es6的又一特性,举个例子:
//es5 拼接字符串
var a='world';
console.log("hello "+a); //hello world
//es6 拼接字符串
let b="world";
console.log(`hello ${b}`); //hello world
使用 ` ` 将整个字符串包裹起来,而在其中使用 ${} 来包裹一个变量或者一个表达式。
3.箭头函数
函数的快捷写法,不需要通过 function 关键字创建函数,并且还可以省略 return 关键字。
//es5 声明函数的方式是这样的
var add=function (a,b){
var a=20;
var b=30;
return a+b;
}
//es6箭头函数
const add1=()=>{
const a=20;
const b=30;
return a+b;
}
另外,箭头函数中无this,使用this会导致未知的错误。
4.解析结构
析构赋值让我们从 Object 或 Array 里取部分数据存为变量。
举个例子:
// 首先有这么一个对象
const props = {
className: 'tiger-button',
loading: false,
clicked: true,
disabled: 'disabled'
}
假设我们需要取props中的classname和clicked属性
//es5
var a=props.className;
var b=props.clicked;
//es6
const ab={className,clicked}=props;
例子2,数组:
const arr=[1,2,3];
//es6
const [a,b,c]=arr;
console.log(a); //1
//es5
var a=arr[0];
var b=arr[1];
console.log(a) //1
5.对象字面量及class
- 首先在于创建对象时的简写,当对象的属性是一个变量时,可以直接使用:
//es6
const name="xiaom";
const age=18;
const oDev={
name,
age
}
console.log(oDev.name);// xiaom
//es5
var name="xiaoh";
var age=28;
var oDD={
name:name,
age:age
}
console.log(oDD.name);
- 在es6对象中方法的function声明可以省略
//es6
const oFF={
a:1,
add(m,n){return m+n}
}
oFF.add(3,5)// 8
//es5
var oDD={
addi:function(m,n){
return m+n
}
}
oDD.addi(8,9)
- class语法
//在es5中我们创建对象大约是这样
7.展开运算符(spread operator)
展开运算符...
是es6的一个新特性主要用法有以下几种。
- 用于组装数组或对象
const arr=['a','b','c'];
//新的数组生成可以这样
const arr2=[...arr,'d'];
console.log(arr2); //a,b,c,d
const oDe={
a:1,
b:2,
c:3
}
const oDe2={
...oDe,
d:5,
e:4
}
console.log(oDe2) //{a: 1, b: 2, c: 3, d: 5, e: 4}
- 获取数组的部分项
const arr=['a','b','c'];
[first,...rest]=arr;
console.log(rest); //["b","c"]
- 收集函数参数为数组
function directions(first,...rest){
console.log(rest)
}
directions(1,3,3,4,4,54,5) //[3, 3, 4, 4, 54, 5]
- 代替apply
const foo=(x,y,z)=>x+y+z;
const arr=[1,3,5]
//es5
foo.apply(null,arr);
//es6
foo(...arr);
8.promises
一个实例
function fn(num){
return new Promise(function(resolve,reject){
if(typeof num==='number'){
resolve();
}else{
reject();
}
})
.then(function(){
console.log("参数是一个数字")
})
.then(null,function(){
console.log("参数不是一个数字")
})
}
fn("1234");
fn(1234);
在Promise对象的构造函数中,将一个函数作为第一个参数。而这个函数,就是用来处理Promise的状态变化。
new Promise(function(resolve, reject) {
if(true) { resolve() };
if(false) { reject() };
})
上面的resolve和reject也是函数,他们的作用是分别将状态改成resolvedg和rejected.
promise中的数据传递
var fn=function(num){
return new Promise(function(resolve,reject){
if(typeof num==='number'){
resolve(num);
}else{
reject("type err")
}
}).then(function(num){
console.log(num+8) ;
return num
})
}
fn().then(function(num){
console.log('first:'+num);
return num+1;
})
.then(function(num){
console.log('second:'+num);
return num+=1;
});
promise的数据传递就是通过resolve()获取返回的参数,再通过then
函数进行处理。
promise.all与promise.race
这两个都是在函数参数不止一个的时使用。比如ajax中我们要等待返回两个response后才能进行操作,此时,如果要等到两个response都为resolved时才操作时就使用promise.all
,如果只要有一个返回就可以进行操作则使用promise.race
:
//伪代码
//需要两个参数res1,res2同时为resolved状态。
function renderAll(){
return promise.all([res1,res2])
}
renderAll().then(function(value){
console.log(.....) //需要处理的代码
})
//两个状态只要有一个为resolved就可以继续执行;
function renderRace(){
return promise.race([res1,res2])
}
renderRace.then(function(value){
console.log(.....)
})
9.Generator
形式上,Generator 函数是一个普通函数,但是有两个特征。
一是,function关键字与函数名之间有一个星号;
二是,函数体内部使用yield表达式,定义不同的内部状态(yield在英语里的意思就是“产出”)。
function* bar(){
console.log("dadfa");
yield "hello";
yield "world";
return 666;
}
const gen=bar();
console.log(gen) //返回一个对象bar,并不会执行bar中的代码;
//只有在调用nexe()方法时,bar函数才会执行,并且只执行到yield处,并返回一个对象,拥有value和done属性
gen.next() //dadfa {value:"hello" done:false}
gen.next() //{value: "world", done: false}
gen.next() //{value: 666, done: true}
gen.next() //{value: undefined, done: true}
//每调用一次next()方法,函数向下一个yield语句进行一次,返回相应的value值,直到完成return语句,此时返回对象的done值变为true,表示执行结束。
10.scync函数
11.es6 Modules
Modules 中文模板的意思,在react及vue等js框架中最基本的使用。
主要通过create-react-app 来熟悉使用
准备工作
- 保证电脑安装了node.js及npm
- 有一个方便的命令行工具如Git bash
开始
1.安装create-react-app
使用npm全局安装,如下:
$ npm install create-react-app -g
2.通过create-react-app来创建项目
首先,找到一个你想创建项目的地址,新建一个项目根目录文件夹,假设为develope
,然后来到这个文件夹进行Git bash ;输入以下命令来创建一个es6项目:
$ create-react-app es6app
这个过程比较长,需要耐心等待。此时你能看到develope文件下有了一个es6app文件夹:
$ cd es6app //进入文件夹
$ ls //查看文件列表
我们首次创建项目需要安装项目需要的包:
$ npm install
安装完毕之后,可以进行启动:
$ npm start
此时,会自动跳至http://localhost:3000/
具体模块操作
主要有两个,一个是import一个是export分别用来引用模块和提供接口;
在index.js中,我们可以通过
import rest from './rest'
来导入外部文件夹的内容,在上面这条指令中,rest 是引入模块的名字,一般为文件名,而 ‘./rest’指的是与index.js 同一目录下的文件。
但上述代码引用成功的前提是rest.js中提供了供引用的接口,形式如:
export default{
name,
age,
foo,
bar,
...
}
其中name,age,foo等是rest中提供的可以引用的项目,包括变量,函数,对象等。
另外,通过
export bar=2323;
这种方式提供的接口,需要在index.js中通过import * as rest from './rest'
方式来引入。
常见的引入方式
我们经常会见到如下的引用方式:
import test, { bar, zcar } from './test';
console.log(test);
console.log('bar:', bar);
console.log('zcar:', zcar);
test,仍然表示为export default暴露的对象,而 { bar, zcar }则表示利用解析结构的语法,从整个返回对象中去取得对应的接口。输出结果也就很清晰了。
更常见的:
import React, { Component } from 'react'
此时就更好理解这样写的意思是引用react提供的接口中的componet组件。
本部分为笔记整理,原文请见详解ES6 Modules