ES6、ES7、ES8学习笔记

ES6

学习文档:http://es6.ruanyifeng.com/

变量let和const

var的问题:可以重复声明,无法限制修改,没有块级作用域,只能用函数包裹限制作用域。

let和const

1、不能重复声明。

2、都是有块级作用域,在{ }块内声明的,块外无效。

3、let是变量,可以修改。

4、const是常量,不能修改。

箭头函数

写法:

1、只有一个参数,( ) 可以省略。

2、只有一个return,{ } 可以省略。

function name() { }	//普通函数
() => { }	//箭头函数,去掉function,加上 =>

作用:

1、简写函数。

2、把父级的this传进里面,里面使用this就是在调用父级的this。

注意:ES6默认采用严格模式,因此this不会自动指向window对象,而箭头函数本身并没有this,所以this是undefined。如果还想用this,就不要用使用箭头函数。

rest参数(剩余参数)

收集不定数目的参数,必须放在最后一个参数位置。

名字可随便起,但必须要有 … 表示这是剩余参数。

这个rest参数提供的剩余参数是个数组。

function show(a, b, ...args){
	console.log(args);	//输出 3, 4, 5
}
show(1, 2, 3, 4, 5);

以前的不定参arguments 不要再用了,因为只能提供类似数组的对象。

而剩余参数能显式的表明你想要获取参数,并提供一个真正的数组。

展开运算符(…)

一种简写,比如在数组前面加三个点,效果和直接写数组内容一样。

let arr = [1, 2, 3];
console.log(...arr);	//输出 1,2,3
let arr2 = [...arr];	//...arr等价于1,2,3,所以这里数组arr2和arr相等
let arr3 = [...arr, 4, 5, ...arr2];	//可以随便组合写

对象也能展开。

还可以转换字符串为数组。

[...'hello']	// [ "h", "e", "l", "l", "o" ]

默认参数

function show(a, b = 5){	//直接在此设置默认参数
	console.log(a, b);
}
show(1);	//输出 1,5
show(1, 2);	//输出 1,2

解构赋值

let [a, b, c] = [1, 2, 3];
console.log(a, b, c);		//输出 1, 2, 3

let {x, y, z} = {x: 1, y: 2, z: 3};
console.log(x, y, z);		//输出 1, 2, 3

1、左右结构必须一样,比如左右都是数组,参数和赋值的个数能对应。

2、右边必须是个合法的东西。

3、声明和赋值不能分开,必须写在一句话中。

解构的粒度可以随意调控,如下

let [json, arr, num, str] = [{a: 1, b: 2}, [1, 2, 3], 8, 'abc'];
console.log(json, arr, num ,str);		//输出 {a: 1, b: 2}, [1, 2, 3], 8, "abc"

let [{a, b}, [n1, n2, n3], num, str] = [{a: 1, b: 2}, [1, 2, 3], 8, 'abc'];
console.log(a, b, n1, n2, n3, num, str);		//输出 1, 2, 1, 2, 3, 8, "abc"

数组

新增了一些数组的方法。

1、 map( ) 映射

能遍历数组中的每一个元素,并对每一个元素做操作。

可以在map函数的参数中定义一个函数,写要对数组中的每一个元素做什么操作,最后可以return返回结果。

let arr = [1, 2 , 3]
let double = arr.map(function(item){
	return item*2
}
let double2 = arr.map(item => item*2)	//上面函数的简写
console.log(double)		//输出 [2, 4,  6]

let score = [22, 70, 61, 45]
let result = score.map(item => item >= 60? '及格' : '不及格')
console.log(result)		//输出 ['不及格', '及格', '及格', '不及格']

2、reduce( ) 汇总

使每一个元素依次顺序相邻的运算求出一个值。

第一参数是保存临时的运算结果,第二参数是当前元素,第三参数是运算了第几次(从1开始算)

比如下面求和。

let arr = [1, 2, 3, 4]
let sum = arr.reduce((tmp, item, index) => {
	console.log(tmp, item, index)		//依次输出(1,2,1), (3,3,2), (6,4,3)
	return tmp + item
})
console.log(sum)		//输出 10

第一次运算时没有临时结果,tmp的值是数组中第一个元素1,和第二个元素2相加等于3。

第二次运算时tmp就保存上一次运算结果3,和数组中第三个元素3相加,如此下去。

下面是求平均数例子。

let arr = [1, 2, 3, 4]
let sum = arr.reduce((tmp, item, index) => {
	if(index != arr.length - 1){		//如果不是最后一次就相加,否则除以数组长度求平均值。
		return tmp + item
	}else{
		return (tmp + item)/arr.length
	}
})
console.log(sum)		//输出 2.5

3、filter( ) 过滤器

过滤数组中的元素。

可以在filter函数的参数中定义一个函数,写对数组的筛选条件,最后可以return返回过滤后结果。

let arr = [12, 4, 8, 9]
let result = arr.filter(item => (item % 3 === 0) ? true : false)	//ture表示保留
//let result = arr.filter(item => item % 3 === 0)   这样简写也行
console.log(result)     //输出 [ 12, 9 ]

let arr = [
    { name: '张三', age: 10 },
    { name: '李四', age: 20 },
]
let result = arr.filter(json => json.age >= 20)
console.log(result)     //输出 [ { name: '李四', age: 20 } ]

4、forEach( ) 循环迭代

迭代循环数组中的元素。

可以在forEach函数的参数中定义一个函数,写对数组中每个元素的遍历操作。

let arr = [12, 2, 7]
let result = arr.forEach((item, index) => console.log(item, index))	//依次输出(12, 0), (2, 1), (7, 2)

5、set( )、Array.from( ) 去重

set( ) 可以接收一个数组或者是类数组对象,自动去除其中的重复元素。

Array.from( ) 可以把类数组对象、可迭代对象转化为数组。

因为Set去重后返回的是一个对象,所以要配合Array.from转换为数组

let arr = [1, 1, '1', '1', null, null , undefined, undefined, NaN, NaN]
console.log(Array.from(new Set(arr)))   //输出 [ 1, '1', null, undefined, NaN ]

6、keys( )、values( )、entries( )、for…of、for…in

keys( )遍历下标values( )遍历entries( )同时遍历下标和值

for … in 遍历数组的下标 key可以遍历对象,但不能与上面那三个方法一起使用

for … of 遍历数组的值 value不能遍历对象,常用于与上面三个方法一起使用

let arr = ['a', 'b', 'c']
for (let i in arr) {
    console.log(i)  //输出 0 1 2
}
for (let i of arr) {
    console.log(i)  //输出 a b c
}
for (let i of arr.keys()) {
    console.log(i)  //输出 0 1 2
}
for (let i of arr.values()) {
    console.log(i)  //输出 a b c
}
for (let [key, value] of arr.entries()) {
    console.log(key + value)  //输出 0a 1b 2c
}
//使用for in遍历对象
let json = { a: 12, b: 5, c: 7 }
for (let i in json) {
    console.log(i)  //输出 a b c
}

startsWith( )、endsWith( )

检测字符串开头或结尾是否包含指定字符串,返回布尔值。

let str = 'abcd'
console.log(str.startsWith('ab'))    //输出 true
console.log(str.endsWith('d'))  //输出 true
console.log(str.endsWith('b'))  //输出 false

字符串模板

使用反引号 `,${变量},可以拆行。

let a = 1
let str = `abc${a}`
console.log(str)    //输出 abc1

面向对象

和Java很像,有class,extend,super,构造函数等之类的。

class User {
    constructor(name, pass) {
        this.name = name
        this.pass = pass
    }
    showName() {
        console.log(this.name)
    }
    showPass() {
        console.log(this.pass)
    }
}

let u1 = new User('abc', 111)   //创建User的实例
u1.showName()   //输出 "abc"
u1.showPass()   //输出 111

//继承
class VipUser extends User {
    constructor(name, pass, level) {
        super(name, pass)   //必须写,表示继承父类
        this.level = level
    }
    showLevel(){    //子类新增的方法
        console.log(this.level)
    }
    showPass(){     //子类重写父类的方法(覆盖)
        console.log(123)
    }
    showPass(level){    //测试能不能重载
        console.log('这是子类重写父类的方法'+ level)
    }
}

let v1 = new VipUser('red', 123, 1)   //创建VipUser的实例
v1.showLevel()  //输出 1
v1.showName()   //调用继承父类的方法,输出 "red"
v1.showPass(2)   //输出 这是子类重写父类的方法2
v1.showPass()  //输出 这是子类重写父类的方法undefined,证明不能重载。

和JAVA的区别之一是不能重载函数,即调用相同函数名的函数时,根据你传递参数不同,调用相应的函数。

对象

1、简写对象的字面量

键值一样时可以简写,里面的函数可以简写, 去掉 :function

var a = 1, b = 2
let obj = {a: a, b: b, show:function(){}}
let obj = {a, b, show(){}}	//简写

2、属性名的定义

obj.foo = true;			// 常见
obj['a' + 'bc'] = 123;	//ES6

var obj = {		// 常见
	foo: true,
	abc: 123
};
var obj = {		// ES6
	[foo]: true,
	['a' + 'bc']: 123
};

例子:

var obj = {
    id0: '00',
    id1: '11',
    name0: '张三',
    name1: '李四'
};
// 把扁平化的对象结构化为两组对象,每组对象包含两组键值对
var arr = [];
for (let i = 0; i < 2; i ++) {
  const item = {
    id: obj[`id${i}`],
    name: obj[`name${i}`]
  };
  arr.push(item);
}
console.log(arr);   //输出 [{id:'00',name:'张三'},{id:'11',name:'李四'}]

3、Object.is( ) 比较

相等运算符(==)和严格相等运算符(===)都有缺点。前者会自动转换数据类型,后者的NaN不等于自身,以及+0等于-0。

JS缺乏一种运算,在所有环境中,只要两个值是一样的,它们就应该相等。该函数就是来弥补这一缺点。

console.log(Object.is('foo', 'foo'))	// true
console.log(Object.is(+0, -0)) 			// false
console.log(Object.is(NaN, NaN)) 		// true
console.log(Object.is(null, null))		//true
console.log(Object.is(undefined, undefined))	//true
console.log(Object.is({ }, { }))		// false,特殊例子
console.log(Object.is([ ], [ ]))		// false,特殊例子

只有空对象或空数组间比较是false,不是同值相等的情况。

4、Object.assign( ) 合并

如果有同名属性,后面会覆盖前面。

const obj1 = { a: 1, b: 1 };
const obj2 = { b: 2, c: 2 };
const obj3 = { c: 3 };
const obj = Object.assign(obj1, obj2, obj3);
console.log(obj)  //输出 { a: 1, b: 2, c: 3 }

5、Object.keys( ),Object.values( ),Object.entries( ) 对象转为数组

我都放在这里一起记。

这三个函数的分别是:

ES5方法,把对象的键返回成一个数组。

ES8方法,把对象的值返回成一个数组。

ES8方法,把对象自身返回成一个数组。

const obj = { a: 'str', b: 1 }
Object.keys(obj)	// ["a", "b"]
Object.values(obj)	// ["str", 1]
Object.entries(obj)	// [ ["a", "str"], ["b", 1] ]

新增的两个方法的作用是方便把对象转成数组后,对值或者键值对遍历,例子如下:

let obj = {a: 1, b: 2, c: 3};
Object.keys(obj).forEach((key) => {			//以前只有key方法
    console.log(key + ": " + obj[key]); 	//输出 a: 1, b: 2, c: 3
})
Object.entries(obj).forEach(([key, value]) => {	//现在entries方法
    console.log(key + ": " + value); 		//输出 a: 1, b: 2, c: 3
})

7、Object.fromEntries( ) 数组转为对象

ES8方法,把键值对数组转为对象。

Object.fromEntries([ ["a", "str"], ["b", 1] ])	// { a: "str", b: 1}

模块

引入:

let { stat, exists, readFile } = require('fs')	//以前
import { stat, exists, readFile } from 'fs'		//ES6

暴露:

module.exports = { stat, exists, readFile }	//以前
export default { stat, exists, readFile }	//ES6

Promise

Promise用来解决地狱回调问题,能把异步操作代码写成同步样子。

Promise对象是个构造函数,通过new创建一个Promise实例,在这实例中有个then方法,看下面例子使用。

// 传统写法
step1( value1 => {
  step2( value1, value2 => {
    step3(value2, value3 => {
      step4(value3, value4 => {
        // ...
      });
    });
  });
});
// Promise 的写法
new Promise(step1)
	.then(step2)
	.then(step3)
	.then(step4);

简单来说就是这样:

function f1(resolve, reject) {
    // 异步代码...
}
var p1 = new Promise(f1);
p1.then(f2).then(f3).then(f4)
// f1的异步操作执行完成,就会执行f2,依次下去

每当new一个Promise实例时,就会立刻执行实例中的异步操作,所以要用函数包裹new的过程,来控制什么时候执行。

Promise实例中还自带两个函数,resolve为成功回调函数,reject为失败回调函数。

读取文件例子如下:

const fs = require('fs')    //引入读取文件模块
getFile = path => { 	//把创建Promise过程放在函数里,按需执行
    return new Promise( (resolve, reject) => {
        fs.readFile(path, 'utf-8', (err, data) => {
            if(err) return reject(err)  //如果有err就返回执行失败回调函数
            resolve(data)   //否则就执行失败回调函数
        })
    })
}
getFile('1.txt')    //调用读取文件函数,由上面函数代码可知,生成第一个promise实例
.then( data => {    //这里.then就是运行上面生成的第一个promise实例
    console.log('成功回调函数' + data)
    return getFile('2.txt') //下面的.then就是在运行这里return的第二个promise实例
}, err => {
    console.log('失败回调函数' + err)
    return getFile('2.txt') //如果前面的promise出错,想让后面的promise继续运行,就在成功和失败回调函数都返回promise实例
})
.then( data => {
    console.log('成功回调函数' + data)
    return getFile('3.txt')
})
.then( data => {
    console.log('成功回调函数' + data)
})

如果前面的promise出错,不想让后面的promise运行,就不要写失败回调函数,同时在最后面加如下代码:

.catch( err => {
    console.log(err)	//promise如果出错,会直接跳到这里运行出错处理代码
})

Promise.all(promiseArray)方法

1、将多个Promise对象实例包装,生成并返回一个新的Promise实例。

2、promise数组中所有的promise实例都变为resolve(成功)的时候,该方法才会返回,并将所有结果传递results数组中。

3、promise数组中任何一个promise为reject的话,则整个Promise.all调用会立即终止,并返回一个reject的新的promise对象。

var p1 = Promise.resolve(1)
var p2 = Promise.resolve(2)
var p3 = Promise.resolve(3)
Promise.all([p1, p2, p3]).then( results => {
    console.log(results)  //输出 [1, 2, 3]
}, err => {
    console.log(err)
})

Promise.all(promiseArray)方法

1、用法和上面一模一样。

2、哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。

3、了解即可。

Generator生成器函数

普通函数,一路到底。

1、 generator函数,中间可以停,到哪停呢,遇到yield就会停

2、调用generator函数,会生成一个generator对象,此时函数还未运行。

**3、**generator对象有个next()方法,调用该方法就会运行generator函数

4、generator函数遇到 yield 会停止时,想要运行就继续用next()启动执行。

5、函数名前加个 * 就是generator函数,不能使用箭头函数

背后实际上生成多个小函数,实现走走停停。

function *show() {
    console.log('1')
    yield
    console.log('2')
}
let genObj = show2()	//用变量接住generator函数创建的generator对象
genObj.next()	//输出 1
genObj.next()	//输出 2
genObj.next()	//最后了,没有结果输出

6、yield 只能在Generator函数内使用

7、yield 既可传参,又可以返回

8、第一个next()只用来启动,传参无效。

传参例子如下

function * show() {
    console.log('1')
    var a = yield
    console.log('2')
    console.log(a)
}
var gen = show()
gen.next()  //输出 1
gen.next()  //输出 2 undefined,因为没有传参,yield没有返回值
var gen = show()
gen.next(10) //输出 1 第一个next只用来启动,传参没用
gen.next(20) //输出 2 20

返回例子如下

function* show() {
    yield 10
    yield 20
}
var gen = show()
console.log(gen.next())   //输出 { value: 10, done: false }
console.log(gen.next())   //输出 { value: 20, done: false }
console.log(gen.next())   //输出 { value: undefined, done: true }

value是每一段小函数的yield值,done表示整个函数完成了没有。

因为最后一段函数是没有yield的,所以输出为undefined。

如果想要最后有值输出,在函数最后return一个值就行。

generator函数的作用把异步操作写成同步代码,如下所示:

runner(function * () {
    let data1 = yield $.ajax({url: 'data1'})
    let data2 = yield $.ajax({url: 'data2'})
    let data2 = yield $.ajax({url: 'data3'})
})

利用yield会暂停,等上一次请求完,下一次才能请求。写成同步代码的样子,非常好看。

promise 只适合一次读一组数据不适合有逻辑性的异步操作。要是一次读了一组数据,还要进行逻辑判断再读不同的数据,就比回调写法还糟糕。

generator适合有逻辑性的异步操作,这是比promise 好的地方是。例子如下,写法完全和平时普通写代码一样。

runner(function * () {
    let data = yield $.ajax({url: 'data '})
    if (data .type == 'VIP') {
        let items = yield $.ajax({url: 'dataVip '})
    } else {
        let items = yield $.ajax({url: 'dataNormal '})
    }
})

在Node.js中,用同步方式写异步,请求数据库:

server.use(function * () {
    let data = yield db.query(`select * from user_table`)
    this.body = data
})

ES7

1、幂运算

用法:3 ** 2 ,这是3的2次方。

由于是运算符,所以可以和 +=一样的用法

let b = 2
b **= 7	//2的7次方,9

2、Includes( )

检测数组是否包含某个东西。第一参数是要找的内容,第二参数是找的起点位置,没有第二参数就默认从头开始找

let arr = ['a', 'b', 'c']
console.log(arr.includes('a'))  //输出 true 
console.log(arr.includes('a', 1))  //输出 false  

ES8

padStart( )、padEnd( )

字符串补全长度的功能,如果某个字符串不够指定长度,会在头部或尾部补全。

第一参数是要补至多少位,第二参数是如果不够位数要补什么,可以不写。

console.log('ab'.padStart(4, '0'))  //输出 00ab
console.log('ab'.padEnd(4, '0'))    //输出 ab00

如果不写第二参数,可以用来做对齐的作用,例子如下:

console.log('0.00')         	
console.log('10,000.00')    
console.log('250,000.00')

输出结果如下:

0.00
10,000.00
250,000.00

使用padStart( )在字符串前面填充至指定位数20:

console.log('0.00'.padStart(20))
console.log('10,000.00'.padStart(20))
console.log('250,000.00'.padStart(20))

输出结果如下,全部右对齐了:

    	  0.00
 	 10,000.00
	250,000.00

使用padEnd()可以在字符串后面填充至指定位数20:

console.log('0.00'.padEnd(20) + '0.00' )
console.log('10,000.00'.padEnd(20) + '10,000.00' )
console.log('250,000.00'.padEnd(20) + '250,000.00')

输过结果如下,因为前面全部是20位,所以后面的数字对齐了:

0.00                0.00
10,000.00           10,000.00
250,000.00          250,000.00

Async/Await

Async函数是用来替代Generator函数的,所以和Generator函数非常相似。

1、 async可以使用箭头函数,generator却不可以。

2、async放在函数名最前面来修饰,这generator的 * 类似。

3、await只能用在async函数中,道理和yield只能在generator中使用一样。

4、直接调用就行,async并不是像generator 一样走走停停,所以和普通函数使用方式一样。

最基础的例子,如图所示,和以前几乎一样:

async function show() {
    console.log(1)
    await
    console.log(2)
}
show()	//输出 1 2

async函数执行异步操作写法:

async () => {
    let data1 = await $.ajax({url: 'data1'})
    let data2 = await $.ajax({url: 'data2'})
    let data2 = await $.ajax({url: 'data3'})
}

5、不用依赖外部,虽然和以前Generator函数使用方式几乎一样,但不用自己写一个runner函数来使用了,已经原生封装写好了。

例子,异步操作2需要异步操作1的结果,异步操作3需要异步操作1和2的结果:

const makeRequest = async () => {
  const value1 = await promise1()
  const value2 = await promise2(value1)
  return promise3(value1, value2)
}

猜你喜欢

转载自blog.csdn.net/weixin_43943881/article/details/87548199
今日推荐