在工做中咱们会经常使用到的一些es6-es10的一些特性还记得多少,今天就让咱们从新复习一遍html
ES6语法es6
1.let声明的变量具备块级做用域,正则表达式
{ let a = 1 } console.log(a); //undefined 变量是在代码块中使用 let 定义的,它的做用域是这个代码块内部,外部没法访问。a{}
2.let声明的全局变量不是全局对象的属性express
var a = 1 console.log(window.a); //1
let a = 1 console.log(window.a); // undefined
3.用let重定义变量会抛出一个语法错误编程
var a = 1 var a = 2 console.log(a) //2 若是是 let ,则会报错 let a = 1 let a = 2 // VM131:1 Uncaught SyntaxError: Identifier 'a' has already been declared // at <anonymous>:1:1
2.Constapi
const
除了具备let
的块级做用域和不会变量提高外,还有就是它定义的是常量,在用const
定义变量后,咱们就不能修改它了,对变量的修改会抛出异常。数组
const A= 123; console.log(A); A = 1; console.log(A); // Uncaught TypeError: Assignment to constant variable.
在 ES6 中新增了不少实用的原生 API,方便开发者对 Array 的操控性更强,如 for…of、from、of、fill、find、findIndex等。promise
3.for…of数据结构
在es5以前遍历数组app
for (var i = 0; i < array.length; i++) { console.log(array[i]); }
在es6以前遍历数组
for (let val of [1,2,3]) { console.log(val); } // 1,2,3
4.Array.prototype.from()
数组是开发中常常用到的数据结构,它很是好用。在 JavaScript 的世界里有些对象被理解为数组,然而缺不能使用数组的原生 API,好比函数中的 arguments、DOM中的 NodeList等。固然,还有一些可遍历的对象,看上去都像数组却不能直接使用数组的 API,由于它们是伪数组(Array-Like)。要想对这些对象使用数组的 API 就要想办法把它们转化为数组,传统的作法是这样的:
let args = [].slice.call(arguments); let imgs = [].slice.call(document.querySelectorAll('img'));
基本原理是使用 call 将数组的 api 应用在新的对象上,换句话说是利用改变函数的上下文来间接使用数组的 api。在 ES6 中提供了新的 api 来解决这个问题,就是 Array.from,代码以下:
let args = Array.from(arguments); let imgs = Array.from(document.querySelectorAll('img'));
5.Array.prototype.of()
Array.of() 方法建立一个具备可变数量参数的新数组实例,而不考虑参数的数量或类型。
Array.of() 和 Array 构造函数之间的区别在于处理整数参数:Array.of(7) 建立一个具备单个元素 7 的数组,而 Array(7) 建立一个长度为7的空数组(注意:这是指一个有7个空位(empty)的数组,而不是由7个undefined组成的数组)。
Array.of(7); // [7] Array.of(1, 2, 3); // [1, 2, 3] Array(7); // [ , , , , , , ] Array(1, 2, 3); // [1, 2, 3]
6.Array.prototype.fill()
fill() 方法用一个固定值填充一个数组中从起始索引到终止索引内的所有元素。不包括终止索引。
let array = [1, 2, 3, 4] array.fill(0, 1, 2) // [1,0,3,4]
7.Array.prototype.find()
find() 方法返回数组中知足提供的测试函数的第一个元素的值,不然返回 undefined。
let array = [5, 12, 8, 130, 44]; let found = array.find(function(element) { return element > 10; }); console.log(found); // 12
8.Array.prototype.findIndex()
findIndex()方法返回数组中知足提供的测试函数的第一个元素的索引。不然返回-1。其实这个和 find() 是成对的,不一样的是它返回的是索引而不是值。
let array = [5, 12, 8, 130, 44]; let found = array.findIndex(function(element) { return element > 10; }); console.log(found); // 1
对于面向对象编程而言,更关注类的声明、属性、方法、静态方法、继承、多态、私有属性。
首先咱们要先来讲明在 JavaScript 世界里如何声明一个 “类”。在 ES6 以前你们都是这么作的:
let Animal = function (type) { this.type = type this.walk = function () { console.log(`I am walking`) } } let dog = new Animal('dog') let monkey = new Animal('monkey')
在 ES6 中把类的声明专业化了,不在用 function 的方式了,请看:
class Animal { constructor (type) { this.type = type } walk () { console.log(`I am walking`) } } let dog = new Animal('dog') let monkey = new Animal('monkey')
10.Setters & Getters
对于类中的属性,能够直接在 constructor 中经过 this 直接定义,还能够直接在类的顶层来定义:
class Animal { constructor (type, age) { this.type = type this._age = age } get age () { return this._age } set age (val) { this._age = val } }
11.静态方法
静态方法是面向对象最经常使用的功能,在 ES5 中利用 function 实现的类是这样实现一个静态方法的。
let Animal = function (type) { this.type = type this.walk = function () { console.log(`I am walking`) } } Animal.eat = function (food) { console.log(`I am eating`); }
在 ES6 中使用 static 的标记是否是静态方法,代码以下:
class Animal { constructor (type) { this.type = type } walk () { console.log(`I am walking`) } static eat () { console.log(`I am eating`) } }
12.继承
面向对象只因此能够应对复杂的项目实现,很大程度上要归功于继承。若是对继承概念不熟悉的同窗,能够自行查询。在 ES5 中怎么实现继承呢?
// 定义父类 let Animal = function (type) { this.type = type } // 定义方法 Animal.prototype.walk = function () { console.log(`I am walking`) } // 定义静态方法 Animal.eat = function (food) { console.log(`I am eating`) } // 定义子类 let Dog = function () { // 初始化父类 Animal.call(this, 'dog') this.run = function () { console.log('I can run') } } // 继承 Dog.prototype = Animal.prototype
从代码上看,是否是很繁琐?并且阅读性也较差。再看看 ES6 是怎么解决这些问题的:
class Animal { constructor (type) { this.type = type } walk () { console.log(`I am walking`) } static eat () { console.log(`I am eating`) } } class Dog extends Animal { constructor () { super('dog') } run () { console.log('I can run') } }
对于函数而言,常常会用到参数,关于参数的默认值一般都是写在函数体中,如在 ES5 的时候你们都会这么写:
function f (x, y, z) { if (y === undefined) y = 7; if (z === undefined) z = 42; return x + y + z; }; f(1) === 50;
当一个函数有不少参数涉及初始化的时候,这样写代码极其丑陋,因此在 ES6 中改变了对这种知识的写法:
function f (x, y = 7, z = 42) { return x + y + z } f(1) === 50
14.Rest Parameter
在写函数的时候,部分状况咱们不是很肯定参数有多少个,好比求和运算,以前都是这么作的:
function sum () { let num = 0 Array.prototype.forEach.call(arguments, function (item) { num += item * 1 }) return num } console.log(sum(1, 2, 3))// 6 console.log(sum(1, 2, 3, 4))// 10
其实在上面说过,这个代码在 ES5 中能够这么写,在 ES6 就不能这么写了,由于 arguments 的问题。如今须要这样写:
function sum (...nums) { let num = 0 nums.forEach(function (item) { num += item * 1 }) return num } console.log(sum(1, 2, 3))// 6 console.log(sum(1, 2, 3, 4))// 10
固然,Rest Parameter 也能够和其余参数一块儿来用,好比:
function sum (base, ...nums) { let num = base nums.forEach(function (item) { num += item * 1 }) return num } console.log(sum(30, 1, 2, 3))// 36 console.log(sum(30, 1, 2, 3, 4))// 40
15.箭头函数
箭头函数能够说是 ES6 很大的福利了,无论你是函数式爱好者仍是面向对象开发者,函数是必需要用到的东西。以前声明函数须要使用 function,以下:
function hello () { console.log('say hello') } // 或 let hello = function () { console.log('say hello') }
如今能够这样作了:
let hello = () => { console.log('say hello') }
若是带参数该怎么作呢?
let hello = (name) => { console.log('say hello', name) } // 或者 let hello = name => { console.log('say hello', name) }
16.Enhanced Object Properties(加强对象属性)
在 ES6 以前 Object 的属性必须是 key-value 形式,以下:
var x = 0, y = 0; obj = { x: x, y: y };
在 ES6 以后是能够用简写的形式来表达:
var x = 0, y = 0 obj = { x, y }
17.Object.assign()
Object.assign() 方法用于将全部可枚举属性的值从一个或多个源对象复制到目标对象,它将返回目标对象。
const target = { a: 1, b: 2 } const source = { b: 4, c: 5 } const returnedTarget = Object.assign(target, source) console.log(target) // expected output: Object { a: 1, b: 4, c: 5 } console.log(returnedTarget) // expected output: Object { a: 1, b: 4, c: 5 }
从语法上能够看出源对象的个数是不限制的(零个或多个),若是是零个直接返回目的对象,若是是多个相同属性的会被后边的源对象的属相覆盖。
let s = Object.assign({ a: 1 }) // {a: 1}
18.RegExp
Sticky
除了u修饰符,ES6还为正则表达式添加了y修饰符,叫作“粘连”(sticky)修饰符。
y修饰符的做用与g修饰符相似,也是全局匹配,后一次匹配都从上一次匹配成功的下一个位置开始。不一样之处在于,g修饰符只要剩余位置中存在匹配就可,而y修饰符确保匹配必须从剩余的第一个位置开始,这也就是“粘连”的涵义。
const s = 'aaa_aa_a' const r1 = /a+/g const r2 = /a+/y r1.exec(s) // ["aaa"] r2.exec(s) // ["aaa"] r1.exec(s) // ["aa"] r2.exec(s) // null
19.Unicode
ES6对正则表达式添加了u修饰符,含义为“Unicode模式”,用来正确处理大于 \uFFFF
的Unicode字符。也就是说,会正确处理四个字节的UTF-16编码。
/^\uD83D/u.test('\uD83D\uDC2A') // false /^\uD83D/.test('\uD83D\uDC2A') // true
上面代码中,\uD83D\uDC2A
是一个四个字节的UTF-16编码,表明一个字符 “?”。可是,ES5不支持四个字节的UTF-16编码,会将其识别为两个字符,致使第二行代码结果为true。加了u修饰符之后,ES6就会识别其为一个字符,因此第一行代码结果为false。
(1)电字符
点(.)字符在正则表达式中,含义是除了换行符之外的任意单个字符。对于码点大于 0xFFFF 的 Unicode 字符,点字符不能识别,必须加上u修饰符。
let s = '?'; // /^.$/.test(s) // false /^.$/u.test(s) // true
(2).Unicode字符表示法
ES6新增了使用大括号表示Unicode字符,这种表示法在正则表达式中必须加上u修饰符,才能识别。
/\u{61}/.test('a') // false /\u{61}/u.test('a') // true /\u{20BB7}/u.test('?') // true
(3)量词
使用u修饰符后,全部量词都会正确识别码点大于0xFFFF的Unicode字符。
/a{2}/.test('aa') // true /a{2}/u.test('aa') // true /?{2}/.test('??') // false /?{2}/u.test('??') // true
(4) 预约义模式
u修饰符也影响到预约义模式,可否正确识别码点大于0xFFFF的Unicode字符。
/^\S$/.test('?') // false /^\S$/u.test('?') // true
上面代码的\S是预约义模式,匹配全部不是空格的字符。只有加了u修饰符,它才能正确匹配码点大于0xFFFF的Unicode字符。
利用这一点,能够写出一个正确返回字符串长度的函数。
function codePointLength(text) { const result = text.match(/[\s\S]/gu); return result ? result.length : 0; } const s = '??'; s.length // 4 codePointLength(s) // 2
(5) i修饰符
有些Unicode字符的编码不一样,可是字型很相近,好比,\u004B与\u212A都是大写的K。
/[a-z]/i.test('\u212A') // false /[a-z]/iu.test('\u212A') // true
在 ES6 以前对字符串的处理是至关的麻烦,看以下场景:
1. 字符串很长要换行
字符串很长包括几种情形一个是开发时输入的文本内容,一个是接口数据返回的文本内容。若是对换行符处理不当,就会带来异常。
2. 字符串中有变量或者表达式
若是字符串不是静态内容,每每是须要加载变量或者表达式,这个也是很常见的需求。以前的作法是字符串拼接:
var a = 20 var b = 10 var c = 'JavaScript' var str = 'My age is ' + (a + b) + ' and I love ' + c console.log(str)
从 ES6 开始能够这样定义字符串了。
`string text` `string text line 1 string text line 2` `string text ${expression} string text` 在这里你能够任意插入变量或者表达式,只要用 ${} 包起来就好。
21解构赋值
在 ES6 中新增了变量赋值的方式:解构赋值。若是对这个概念不了解,咱们能够快速展现一个小示例一睹风采:
let arr = ['Ilya', 'Kantor'] let firstName = arr[0] let surname = arr[1]
想从数组中找出有意义的项要单独赋值给变量(一一的写),在 ES6 中就能够这样写了:
let [firstName, surname] = ['Ilya', 'Kantor'] console.log(firstName) // Ilya console.log(surname) // Kantor
22.Promise
首先要说明 Promise 就是为了解决“回调地狱”问题的,它能够将异步操做的处理变得很优雅。若是咱们使用 Promise 来解决上面那个问题该怎么作呢?
function loadScript (src) { return new Promise((resolve, reject) => { let script = document.createElement('script') script.src = src script.onload = () => resolve(script) script.onerror = (err) => reject(err) document.head.append(script) }) } loadScript('1.js') .then(loadScript('2.js'), (err) => { console.log(err) }) .then(loadScript('3.js'), (err) => { console.log(err) })
经过建立 Promise 对象开启一个异步操做的过程,通常用几步完成屡次异步操做:
1.Promise.prototype.then()
var promise = new Promise(function (resolve, reject) { resolve('传递给then的值') }) promise.then(function (value) { console.log(value) }, function (error) { console.error(error) })
这段代码建立一个 Promise 对象,定义了处理 onFulfilled 和 onRejected 的函数(handler),而后返回这个 Promise 对象。
这个 Promise 对象会在变为 resolve 或者 reject 的时候分别调用相应注册的回调函数。
当 handler 返回一个正常值的时候,这个值会传递给 Promise 对象的 onFulfilled 方法。
定义的 handler 中产生异常的时候,这个值则会传递给 Promise 对象的 onRejected 方法
2.Promise.resolve()
通常状况下咱们都会使用 new Promise()
来建立 Promise 对象,可是除此以外咱们也可使用其余方法。
Promise.resolve(42).then(function (value) { console.log(value) })
在这段代码中的 resolve(42) 会让这个 Promise 对象当即进入肯定(即resolved)状态,并将 42 传递给后面 then 里所指定的 onFulfilled 函数。
3.Promise.reject()
Promise.reject(error) 是和 Promise.resolve(value) 相似的静态方法,是 new Promise() 方法的快捷方式。
new Promise(function (resolve, reject) { reject(new Error('出错了')) })
4.Promise.prototype.catch()
捕获异常是程序质量保障最基本的要求,可使用 Promise 对象的 catch 方法来捕获异步操做过程当中出现的任何异常。
function test () { return new Promise((resolve, reject) => { reject(new Error('es')) }) } test().catch((e) => { console.log(e.message) // es })
5.Promise.all()
var p1 = Promise.resolve(1) var p2 = Promise.resolve(2) var p3 = Promise.resolve(3) Promise.all([p1, p2, p3]).then(function (results) { console.log(results) // [1, 2, 3] })
Promise.all 生成并返回一个新的 Promise 对象,因此它可使用 Promise 实例的全部方法。参数传递promise数组中全部的 Promise 对象都变为resolve的时候,该方法才会返回, 新建立的 Promise 则会使用这些 promise 的值。
若是参数中的任何一个promise为reject的话,则整个Promise.all调用会当即终止,并返回一个reject的新的 Promise 对象。
因为参数数组中的每一个元素都是由 Promise.resolve 包装(wrap)的,因此Paomise.all 能够处理不一样类型的 promose对
6.Promise.race()
var p1 = Promise.resolve(1) var p2 = Promise.resolve(2) var p3 = Promise.resolve(3) Promise.race([p1, p2, p3]).then(function (value) { console.log(value) // 1 })
Promise.race 生成并返回一个新的 Promise 对象。
参数 promise 数组中的任何一个 Promise 对象若是变为 resolve 或者 reject 的话, 该函数就会返回,并使用这个 Promise 对象的值进行 resolve 或者 reject。
23.Reflect
Reflect 是一个内置的对象,它提供拦截 JavaScript 操做的方法,这些方法与处理器对象的方法相同。Reflect不是一个函数对象,所以它是不可构造的。
Reflect.apply(Math.floor, undefined, [1.75]) // 1; Reflect.apply(String.fromCharCode, undefined, [104, 101, 108, 108, 111]) // "hello" Reflect.apply(RegExp.prototype.exec, /ab/, ['confabulation']).index // 4 Reflect.apply(''.charAt, 'ponies', [3]) // "i"
该方法与ES5中Function.prototype.apply()方法相似:调用一个方法而且显式地指定this变量和参数列表(arguments) ,参数列表能够是数组,或相似数组的对象。
Function.prototype.apply.call(Math.floor, undefined, [1.75]);
2.Reflect.construct()
Reflect.construct() 方法的行为有点像 new 操做符 构造函数 , 至关于运行 new target(…args).
var d = Reflect.construct(Date, [1776, 6, 4]) d instanceof Date // true d.getFullYear() // 1776
3.Reflect.defineProperty()
静态方法 Reflect.defineProperty() 基本等同于 Object.defineProperty() 方法,惟一不一样是返回 Boolean 值。
const student = {} Reflect.defineProperty(student, 'name', { value: 'Mike' }) // true student.name // "Mike"
4.Deflect.deleteProperty()
Reflect.deleteProperty 容许你删除一个对象上的属性。返回一个 Boolean 值表示该属性是否被成功删除。它几乎与非严格的 delete operator 相同。
var obj = { x: 1, y: 2 }; Reflect.deleteProperty(obj, "x"); // true obj; // { y: 2 } var arr = [1, 2, 3, 4, 5]; Reflect.deleteProperty(arr, "3"); // true arr; // [1, 2, 3, , 5] // 若是属性不存在,返回 true Reflect.deleteProperty({}, "foo"); // true // 若是属性不可配置,返回 false Reflect.deleteProperty(Object.freeze({foo: 1}), "foo"); // false
5.Reflect.get()
Reflect.get() 方法的工做方式,就像从 object (target[propertyKey]) 中获取属性,但它是做为一个函数执行的。
// Object var obj = { x: 1, y: 2 } Reflect.get(obj, 'x') // 1 // Array Reflect.get(['zero', 'one'], 1) // "one" // Proxy with a get handler var x = { p: 1 } var obj = new Proxy(x, { get (t, k, r) { return k + 'bar' } }) Reflect.get(obj, 'foo') // "foobar"
6.Reflect.getOwnPropertyDescriptor()
静态方法 Reflect.getOwnPropertyDescriptor() 与 Object.getOwnPropertyDescriptor() 方法类似。若是在对象中存在,则返回给定的属性的属性描述符,不然返回 undefined。
Reflect.getOwnPropertyDescriptor({ x: 'hello' }, 'x') // {value: "hello", writable: true, enumerable: true, configurable: true} Reflect.getOwnPropertyDescriptor({ x: 'hello' }, 'y') // undefined Reflect.getOwnPropertyDescriptor([], 'length') // {value: 0, writable: true, enumerable: false, configurable: false}
7.Reflect.getPrototypeOf()
静态方法 Reflect.getPrototypeOf() 与 Object.getPrototypeOf() 方法是同样的。都是返回指定对象的原型(即,内部的 [[Prototype]] 属性的值)。
8.Reflect.has()
Reflect.has 用于检查一个对象是否拥有某个属性, 至关于in 操做符
9.Reflect.set()
Reflect.set 方法容许你在对象上设置属性。它的做用是给属性赋值而且就像 property accessor 语法同样,可是它是以函数的方式。
// Object var obj = {}; Reflect.set(obj, "prop", "value"); // true obj.prop; // "value" // Array var arr = ["duck", "duck", "duck"]; Reflect.set(arr, 2, "goose"); // true arr[2]; // "goose" // It can truncate an array. Reflect.set(arr, "length", 1); // true arr; // ["duck"]; // With just one argument, propertyKey and value are "undefined". var obj = {}; Reflect.set(obj); // true Reflect.getOwnPropertyDescriptor(obj, "undefined"); // { value: undefined, writable: true, enumerable: true, configurable: true }
10.Reflect.setPrototypeOf()
Reflect.setPrototypeOf 方法改变指定对象的原型 (即,内部的 [[Prototype]] 属性值)
Reflect.setPrototypeOf({}, Object.prototype); // true // It can change an object's [[Prototype]] to null. Reflect.setPrototypeOf({}, null); // true // Returns false if target is not extensible. Reflect.setPrototypeOf(Object.freeze({}), null); // false // Returns false if it cause a prototype chain cycle. var target = {}; var proto = Object.create(target); Reflect.setPrototypeOf(target, proto); // false
24.Proxy
let p = new Proxy(target, handler)
从服务端获取的数据但愿是只读,不容许在任何一个环节被修改。
// response.data 是 JSON 格式的数据,来自服务端的响应 // 在 ES5 中只能经过遍历把全部的属性设置为只读 for (let [key] of Object.entries(response.data)) { Object.defineProperty(response.data, key, { writable: false }) }
若是咱们使用 Proxy 就简单不少了:
let data = new Proxy(response.data, { set(obj, key, value) { return false } })
25.Generator
什么是 JavaScript Generators 呢?通俗的讲 Generators 是能够用来控制迭代器的函数。它们能够暂停,而后在任什么时候候恢复。若是这句话很差理解,能够看下接下来的示例。
ES5以前作法
for (let i = 0; i < 5; i += 1) { console.log(i) } // this will return immediately 0 -> 1 -> 2 -> 3 -> 4
用 Generator
function * generatorForLoop () { for (let i = 0; i < 5; i += 1) { yield console.log(i) } } const genForLoop = generatorForLoop() console.log(genForLoop.next()) // first console.log - 0 console.log(genForLoop.next()) // 1 console.log(genForLoop.next()) // 2 console.log(genForLoop.next()) // 3
对比下代码,常规的循环只能一次遍历完全部值,Generator 能够经过调用 next 方法拿到依次遍历的值,让遍历的执行变得“可控”。
function * gen () { yield 1 yield 2 yield 3 } let g = gen() // "Generator { }"
这个是 Generator 的定义方法,有几个点值得注意:
yield 表达式的返回值是 undefined,可是遍历器对象的 next 方法能够修改这个默认值
function * gen () { let val val = yield 1 console.log(`1:${val}`) // 1:undefined val = yield 2 console.log(`2:${val}`) // 2:undefined val = yield 3 console.log(`3:${val}`) // 3:undefined } var g = gen() console.log(g.next()) // {value: 1, done: false} console.log(g.next()) // {value: 2, done: false} console.log(g.next()) // {value: 3, done: false} console.log(g.next()) // {value: undefined, done: true}
yeild * 是委托给另外一个遍历器对象或者可遍历对象
function * gen () { let val val = yield 1 console.log(`1:${val}`) // 1:undefined val = yield 2 console.log(`2:${val}`) // 2:undefined val = yield [3, 4, 5] console.log(`3:${val}`) // 3:undefined }
enerator 对象的 next 方法,遇到 yield 就暂停,并返回一个对象,这个对象包括两个属性:value 和 done。
26.module
在 ES6 以前,JS 文件之间的导入、导出是须要借助 require.js、sea.js。如今,你们可使用 import、export 来实现原生 JavaScript 的导入、导出了。
导出变量或者常量
export const name = 'hello' export let addr = 'BeiJing City' export var list = [1, 2 , 3]
const name = 'hello' let addr = 'BeiJing City' var list = [1, 2 , 3] export { name as cname, addr as caddr } export default list
ES7语法
1.Array.prototype.includes
Array.prototype.includes() 方法用来判断一个数组是否包含一个指定的值,根据状况,若是包含则返回 true,不然返回false。
let array1 = [1, 2, 3] console.log(array1.includes(2)) // expected output: true var pets = ['cat', 'dog', 'bat'] console.log(pets.includes('cat')) // expected output: true console.log(pets.includes('at')) // expected output: false
在 ES7 以前想判断数组中是否包含一个元素,基本能够这样写:
console.log(array1.find(function (item) { return item === 2 }))
2.Math.pow
咱们一直都是这样用的:
console.log(Math.pow(2, 3)) // 8(2的三次方)
在 ES7 能够这样写了:
console.log(2 ** 3)
ES8语法
1.Async/Await
async 和 await 是 Promise 的拓展,若是对 Promise 还不了解的话,请移步 Promise 章节进行学习。
async function firstAsync () { return 27 } firstAsync().then(console.log) // 27
也就是说上面的代码等同于:
async function firstAsync () { return Promise.resolve(27) }
async 的做用咱们清楚了,await呢?话很少说:
async function firstAsync () { let promise = new Promise((resolve, reject) => { setTimeout(() => resolve("Now it's done!"), 1000) }) // wait until the promise returns us a value let result = await promise // "Now it's done!" return result } firstAsync().then(console.log)
这段代码使用了 await,从这个字面的意思看就是“等待”,它等什么呢?很简单,它等 Promise 返回结果。上面代码的意思是 async 开启了一个 Promise 对象,这个函数内部嵌套了一个 Promise 操做,这个操做须要等 1 秒才返回 “Now it’s done!” 这个结果。也就是说 await 在拿到这个结果以前不会继续执行,一直等到结果才日后继续执行,也就是 async function 声明的 Promise 才会响应(console.log才执行)。
常规
async function firstAsync () { let result = await 27 return result } firstAsync().then(console.log) // 27
对象
async function firstAsync () { let result = await { a: 1 } return result } firstAsync().then(console.log) // { a: 1 }
非 Promise 对象将用 Promise.resolve 来包装,而 await 后边的值做为 resolve 的参数。
2. await 不能够脱离 async 单独使用
function firstAsync() { let promise = Promise.resolve(10); let result = await promise; // Syntax error }
2.Object.values()
Object.values() 返回一个数组,其元素是在对象上找到的可枚举属性值。属性的顺序与经过手动循环对象的属性值所给出的顺序相同(for…in,可是for…in还会遍历原型上的属性值)。
let grade = { 'lilei': 98, 'hanmei': 87 } console.log(Object.values(grade)) // [98, 87]
3.Object.entries
Object.entries()方法返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for…in 循环遍历该对象时返回的顺序一致。(区别在于 for-in 循环也枚举原型链中的属性)
let grade = { 'lilei': 98, 'hanmei': 87 } for (let [key, value] of grade) { console.log(key, value) // Uncaught TypeError: grade is not iterable }
咱们知道 Object 是不可直接遍历的,上述代码足以说明直接遍历触发了错误。若是使用 Object.entries() 则能够完成遍历任务。
let grade = { 'lilei': 98, 'hanmei': 87 } for (let [k, v] of Object.entries(grade)) { console.log(k, v) // lilei 98 // hanmei 87 }
在 ES8 中 String 新增了两个实例函数 String.prototype.padStart 和 String.prototype.padEnd,容许将空字符串或其余字符串添加到原始字符串的开头或结尾。
这两个方法有什么用武之地呢?回忆下咱们处理日期的时候常常要格式化,好比 0一、0二、10等。
for (let i = 1; i < 31; i++) { if (i < 10) { console.log(`0${i}`) } else { console.log(i) } }
以前输出1号到31号,须要手动判断是否小于10号,小于的在前面增长 0。如今能够这样作了:
for (let i = 1; i < 31; i++) { console.log(i.toString().padStart(2, '0')) }
String.prototype.padStart 和 String.prototype.padEnd 用法是相同的,只是一个在开头补白一个在结尾。
5.Object.getOwnPropertyDescriptors()
想理解 Object.getOwnPropertyDescriptors 这个方法以前,首先要弄懂什么是描述符(descriptor)?
const data = { Portland: '78/50', Dublin: '88/52', Lima: '58/40' }
仍是上述那个对象,这里有 key 和 value,上边的代码把全部的 key、value 遍历出来,若是咱们不想让 Lima 这个属性和值被枚举怎么办?
Object.defineProperty(data, 'Lima', { enumerable: false }) Object.entries(data).map(([city, temp]) => { console.log(`City: ${city.padEnd(16)} Weather: ${temp}`) // City: Portland Weather: 78/50 // City: Dublin Weather: 88/52 })
很成功,Lima 没有被遍历出来,那么 defineProperty 的第三个参数就是描述符(descriptor)。这个描述符包括几个属性:
ES9语法
1.for await of
咱们知道 for…of 是同步运行的,有时候一些任务集合是异步的,那这种遍历怎么办呢?
function Gen (time) { return new Promise(function (resolve, reject) { setTimeout(function () { resolve(time) }, time) }) } async function test () { let arr = [Gen(2000), Gen(100), Gen(3000)] for (let item of arr) { console.log(Date.now(), item.then(console.log)) } } test() // 1560090138232 Promise {<pending>} // 1560090138234 Promise {<pending>} // 1560090138235 Promise {<pending>} // 100 // 2000 // 3000
await 的做用,它能够中断程序的执行直到这个 Promise 对象的状态发生改变,
function Gen (time) { return new Promise(function (resolve, reject) { setTimeout(function () { resolve(time) }, time) }) } async function test () { let arr = [Gen(2000), Gen(100), Gen(3000)] for (let item of arr) { console.log(Date.now(), await item.then(console.log)) } } test() // 2000 // 1560091834772 undefined // 100 // 1560091836774 undefined // 3000 // 1560091836775 undefined
从返回值看确实是按照任务的前后顺序进行的,其中原理也有说明是利用了 await 中断程序的功能。不过,在 ES9 中也能够用 for…await…of 的语法来操做:
function Gen (time) { return new Promise(function (resolve, reject) { setTimeout(function () { resolve(time) }, time) }) } async function test () { let arr = [Gen(2000), Gen(100), Gen(3000)] for await (let item of arr) { console.log(Date.now(), item) } } test() // 1560092345730 2000 // 1560092345730 100 // 1560092346336 3000
2.Promise.prototype.finally()
Promise.prototype.finally() 方法返回一个Promise,在promise执行结束时,不管结果是fulfilled或者是rejected,在执行then()和catch()后,都会执行finally指定的回调函数。这为指定执行完promise后,不管结果是fulfilled仍是rejected都须要执行的代码提供了一种方式,避免一样的语句须要在then()和catch()中各写一次的状况。
let connection; db.open() .then(conn => { connection = conn; return connection.select({ name: 'Jane' }); }) .then(result => { // Process result // Use `connection` to make more queries }) ··· .catch(error => { // handle errors }) .finally(() => { connection.close(); });
3.Object Rest Spread
前面在讲 function 的 Rest & Spread 方法,忘却的同窗能够去复习下。在 ES9 新增 Object 的 Rest & Spread 方法,直接看下示例:
const input = { a: 1, b: 2 } const output = { ...input, c: 3 } console.log(output) // {a: 1, b: 2, c: 3}
ES10语法
JSON.stringify 在 ES10 修复了对于一些超出范围的 Unicode 展现错误的问题。由于 JSON 都是被编码成 UTF-8,因此遇到 0xD800–0xDFFF 以内的字符会由于没法编码成 UTF-8 进而致使显示错误。在 ES10 它会用转义字符的方式来处理这部分字符而非编码的方式,这样就会正常显示了。
JSON.stringify('\u{D800}') === '"\\ud800"' // true
2.Array.prototype.flat()
flat() 方法会按照一个可指定的深度递归遍历数组,并将全部元素与遍历到的子数组中的元素合并为一个新数组返回。
const newArray = arr.flat(depth) 语法
const numbers = [1, 2, [3, 4, [5, 6]]] console.log(numbers.flat()) // [1, 2, 3, 4, [5, 6]]
此时 flat 的参数没有设置,取默认值 1,也就是说只扁平化向下一级,遇到 [3, 4, [5, 6]] 这个数组会扁平会处理,不会再继续遍历内部的元素是否还有数组
const numbers = [1, 2, [3, 4, [5, 6]]] console.log(numbers.flat(2)) // [1, 2, 3, 4, 5, 6]
3.Array.prototype.flatMap()
flatMap() 方法首先使用映射函数映射每一个元素,而后将结果压缩成一个新数组。从方法的名字上也能够看出来它包含两部分功能一个是 map,一个是 flat(深度为1)。
const new_array = arr.flatMap(function callback(currentValue[, index[, array]]) { // 返回新数组的元素 }[, thisArg])
参数 | 含义 | 必选 |
callback | 能够生产一个新数组中的元素的函数,能够传三个参数,currentValue,index,array | y |
thisArg | 遍历函数this的指向 | N |
const numbers = [1, 2, 3] numbers.map(x => [x * 2]) // [[2], [4], [6]] numbers.flatMap(x => [x * 2]) // [2, 4, 6]
这个小示例能够简单对比下 map 和 flatMap 的区别。固然还能够看下 MDN 的示例:
let arr = ['今每天气不错', '', '早上好'] arr.map(s => s.split('')) // [["今", "天", "天", "气", "不", "错"],[""],["早", "上", "好"]] arr.flatMap(s => s.split('')) // ["今", "天", "天", "气", "不", "错", "", "早", "上", "好"]
4.String.prototype.trimStart()
trimStart() 方法从字符串的开头删除空格,trimLeft()是此方法的别名。
let str = ' foo ' console.log(str.length) // 8 str = str.trimStart() console.log(str.length) // 5
5.String.prototype.trimEnd()
trimEnd() 方法从一个字符串的右端移除空白字符,trimRight 是 trimEnd 的别名。
let str = ' foo ' console.log(str.length) // 8 str = str.trimEnd() console.log(str.length) // 6
6.String.prototype.matchAll()
matchAll() 方法返回一个包含全部匹配正则表达式及分组捕获结果的迭代器
在了解 matchAll 以前,咱们回顾下 ES10 以前一共有多少种正则所有遍历的方法。
1. RegExp.prototype.exec() with /g
function collectGroup1 (regExp, str) { const matches = [] while (true) { const match = regExp.exec(str) if (match === null) break // Add capture of group 1 to `matches` matches.push(match[1]) } return matches } collectGroup1(/"([^"]*)"/g, `"foo" and "bar" and "baz"`) // [ 'foo', 'bar', 'baz' ]
2. String.prototype.match() with /g
若是用 .match 方法结合 /g 的正则模式,将会把全部的匹配打包成一个数组返回,换句话说全部的捕获被忽略。 'abeabd'.match(/(a)b(?=e)/g) // ["ab"]
不过若是没有使用 /g 的正则模式,.match 的效果和 RegExp.prototype.exec() 是一致的。
3. String.prototype.replace()
function collectGroup1 (regExp, str) { const matches = [] function replacementFunc (all, first) { matches.push(first) } str.replace(regExp, replacementFunc) return matches } collectGroup1(/"([^"]*)"/ug, `"foo" and "bar" and "baz"`) // ["foo", "bar", "baz"]
如今看下 .matchAll 方法,能够这样作:
function collectGroup1 (regExp, str) { let results = [] for (const match of str.matchAll(regExp)) { results.push(match[1]) } return results } collectGroup1(/"([^"]*)"/g, `"foo" and "bar" and "baz"`) // ["foo", "bar", "baz"]
7.Object.fromEntries()
方法 Object.fromEntries() 把键值对列表转换为一个对象,这个方法是和 Object.entries() 相对的。
Object.fromEntries([['foo', 1], ['bar', 2]]) // {foo: 1, bar: 2}
示例
let obj = { abc: 1, def: 2, ghij: 3 } let res = Object.fromEntries( Object.entries(obj) .filter(([ key, val ]) => key.length === 3) .map(([ key, val ]) => [ key, val * 2 ]) ) console.log(res) // res is { 'abc': 2, 'def': 4 }
8.Symbol.prototype.description
咱们知道,Symbol 的描述只被存储在内部的 [[Description]],没有直接对外暴露,咱们只有调用 Symbol 的 toString() 时才能够读取这个属性:
const name = Symbol('My name is axuebin') console.log(name.toString()) // Symbol(My name is axuebin) console.log(name) // Symbol(My name is axuebin) console.log(name === 'Symbol(My name is axuebin)') // false console.log(name.toString() === 'Symbol(My name is axuebin)') // true
toString() 方法返回一个表示当前函数源代码的字符串
function hello (msg) { console.log('hello') } console.log(hello.toString()) // function hello (msg) { // console.log('hello') // }
10.try…catch
在 ES10 以前咱们都是这样捕获异常的:
try { // tryCode } catch (err) { // catchCode }
在这里 err 是必须的参数,在 ES10 能够省略这个参数:
try { console.log('Foobar') } catch { console.error('Bar') }
在 ES10 增长了一个数据类型:BigInt,用于处理超过 2^53 的数字。
const aBigInt = 11n; const aNumber = 156; const aBigInt = BigInt(aNumber); aBigInt === 156n // true typeof aBigInt === bigint // true
以上就是在工做中比较经常使用的es6-es10语法知识点
原文出处:https://www.cnblogs.com/zhoulifeng/p/12259809.html