总结 ES2015 的所有新特性
总结 ES2015 的所有新特性
💥 ES2015(ES6)是改动最大的一个版本,大体如下:
🍏 let、const关键字和块级作用域
在ES6来临之前,我们习惯于var
关键字声明变量,var
声明的变量是属于全局变量,最终会挂载到window对象,这一操作可能会引起一些意外的错误。所以在ES6中加入了const
和let
关键字来声明变量。
let v = 100
v = 200
const a = 1
a = 2; // Uncaught TypeError: Assignment to constant variable.
// 报错,const关键字声明的是一个常量,是不可以改变的(针对于基本数据类型)
{
var a = 100
}
{
let b = 100
}
console.log(a) // output: 100
console.log(b) // 报错,b is not defined.
// let声明的变量只能在当前的`块级作用域({} 之间的区域)`中使用
⚠️ let、const声明的变量存在一个暂时性死区的问题
a = 1;
let a = 0;// Uncaught ReferenceError: Cannot access 'a' before initialization
// 暂时性死区是指使用let、const关键字声明的变量在定义之前是不可以使用的,声明之后才可以使用。
🍐 函数的扩展(函数形参的默认值、箭头函数)
-
函数默认值
// es2015之前 function foo(v) { v = v ? v : 100 return v } // es2015 function bar(v = 100) { return v }
-
箭头函数
function foo(v) { return v`` } // 箭头函数写法 const foo = (v) => { return v } // 简写形式 1 const foo = v => { // 只有一个参数可以省略括号 return v } // 简写形式 2 const foo = v => v // 语句中只有return时可以省略return和花括号
⛅️ 补充
箭头函数与普通函数的区别
- 箭头函数中的this指向的是上一级上下文中的this
- call、apply、bind方法都无法改变箭头函数的this指向
- 箭头函数没有prototype属性
- 箭头函数不能作为构造函数使用
- 也不能使用new方法
- 没有arguments实参列表
🌊 在ES2015中为函数增加的要给name属性,该属性指向函数的名称。
function foo(v) { return v } const bar = v => v console.log(foo.name) // foo console.log(bar.name) // bar
🍋 字符串的扩展
ES2015中引入了模板字符串的概念,使用反引号**( ` )** 定义,模板字符串会保留格式,且可以使用变量。
// 使用 ` 定义模板字符串
let str = `一碗周`
// 模板字符串可以保留格式
let str2 = `一
碗
周`
// 模板字符串可以使用变量
const myName = '一碗周'
let str3 = `author: ${myName}` // 使用 ${} 进行包裹
ES2015还为String和String的示例扩展了一些方法,如下:
方法名 | 描述 |
---|---|
String.fromCodePoint() | 用于从 Unicode 码点返回对应字符 |
String.raw() | 返回一个斜杠都被转义(即斜杠前面再加一个斜杠)的字符串,往往用于模板字符串的处理方法。 |
String.prototype.codePointAt() | 返回字符对应码点(String.fromCodePoint() 的逆操作) |
String.prototype.normalize() | 把字符的不同表示方法统一为同样形式,返回新字符串 (Unicode正规化) |
String.prototype.repeat() | 把字符串重复n次,返回处理后的字符串 |
String.prototype.includes() | 判断是否存在指定字符串 |
String.prototype.startsWith() | 判断字符串是否存在原始字符串的头部 |
String.prototype.endsWith() | 判断字符串是否存在原始字符串的尾部 |
🍉 数组的扩展
ES2015中提供了扩展运算符,即**( … )** ,在数组中使用可以将数组展开,并以逗号分隔。
const arr = [1, 2, 3, 4, 5, 6]
const newArr = [...arr] // 复制数组
console.log(Math.max.call(null, ...arr)) // 将数组中的每一项作为参数使用
除此之外,Array以及数组提供了一系列方法,具体如下:
-
Array.from(): 将类数组对象或者可迭代对象创建一个新的数组,示例代码如下:
function foo() { return Array.from(arguments) // 将 arguments 转换为数组 } console.log(foo(1, 2, 3, 4, 5, 6)) // [ 1, 2, 3, 4, 5, 6 ]
-
Array.of():创建一个具有可变数量参数的新数组实例,示例代码如下:
Array.of(1) // [1] Array.of(true, 1, '一碗周') // [true, 1, '一碗周']
-
Array.prototype.copyWithin(): 浅复制数组的一部分到统一数组中的另一个位置,并返回它,不会改变原数组的长度。示例代码如下:
const arr = [1, 2, 3, 4] // 从索引 2 开始,到结束 将内容复制到索引 0 的位置 arr.copyWithin(0, 2) // [ 3, 4, 3, 4 ]
-
Array.prototype.find(): 根据给定的回调函数,找到匹配的第一个元素,找不到返回undefined ,示例代码如下:
const arr = [1, 2, 3, 4] arr.find(item => item === 2) // 2(表示元素)、
-
Array.prototype.findIndex(): 根据给定的回调函数,找到匹配的第一个元素的索引,找不到返回-1,示例代码如下:
const arr = [1, 2, 3, 4] arr.findIndex(item => item === 2) // 1 (表示索引)
-
Array.prototype.fill(): 将给定值填充数组,示例代码如下:
const arr = [1, 2, 3, 4] // 将给定值填充索引1-3 arr.fill('一碗周', 1, 3) // [ 1, '一碗周', '一碗周', 4 ]
-
Array.prototype.values(),返回一个可迭代的对象,其内容为数组的value,示例代码如下:
const arr = [1, true, '一碗周'] const values = arr.values() for (const i of values) { console.log(i) // 遍历结果 1 true 一碗周 }
-
Array.prototype.entries():返回一个可迭代的对象,其内容是一个数组,索引0为原数组的元素,1为原数组该位置的值,示例代码如下:
const arr = [1, true, '一碗周'] const iterator = arr.entries() console.log(Array.from(iterator)) // [ [ 0, 1 ], [ 1, true ], [ 2, '一碗周' ] ]
🥥 对象的扩展
ES2015中允许对象的属性名和属性值一致时 只写属性名,示例代码如下:
const myName = '一碗周'
const age = 18
const person = { myName, age }
console.log(person) // { myName: '一碗周', age: 18 }
还有允许在定义对象时,允许使用**[ ]**包裹表达式作为属性名,示例代码如下:
const myName = '一碗周'
const age = 18
const person = {
myName,
['a' + 'g' + 'e']: age,
}
console.log(person) // { myName: '一碗周', age: 18 }
-
Object.is():用于比较两个值是否相等,用于解决NaN != NaN, +0 === -0的问题,示例代码如下:
console.log(NaN === NaN) // false console.log(+0 === -0) // true console.log(Object.is(NaN, NaN)) // true console.log(Object.is(+0, -0)) // false
-
Object.assign():将所有可枚举属性的值从一个或多个源对象复制到目标对象,并返回目标对象,示例代码如下:
const person = Object.assign({}, { name: '一碗周' }, { age: 18 }) console.log(person) // { name: '一碗周', age: 18 }
-
Object.getPrototypeOf():获取原型对象。
-
Object.setPrototypeOf():设置原型对象。
🍑 类的概念
在ES2015中提出了类的概念,在语法层面上有了类,示例代码如下:
class Person {
constructor(age) {
// 属性
this.myName = '一碗周'
this.age = age
}
// 静态方法
// 类(class)通过 static 关键字定义静态方法。不能在类的实例上调用静态方法,而应该通过类本身调用。这些通常是实用程序方法,例如创建或克隆对象的功能。
static print() {
console.log()
}
// 访问器
get myName() {
console.log('getter')
return '一碗周'
}
set myName(v) {
console.log('setter' + v)
}
setName(v) {
this.myName = v
}
}
const person = new Person(18)
person.setName('ywanzhou') // 触发 setter 访问器
console.log(person.myName) // 触发 getter 访问器
🍍 模块化
在ES2015中提出了ESModel的模块化规范,这是第一个官方层面的模块化规范,在这个规范中允许我们使用export 导出模块,使用import 引入模块,示例代码如下:
import a from 'm' // 导入模块 m 中的默认导出,将其命名为 a
import a, { b } from 'm' // 导入模块 m 中的默认导出以及单独导入成员 b
import * as A from 'm' // 导入模块中的所有成员
import 'm' // 执行 m 模块
export const b = 1 // 单独导出
export default b // 默认导出
export { b } // 按需导出
export { b as bb } // 改名导出
export { b } from 'm' // 导入模块 m 中的成员 b 并导出
🌶 解构赋值
ES2015新增了解构赋值的语法,允许我们使用按照一定的模式,在数组或者对象中提取指定的值,示例代码如下:
// 数组的解构赋值
let [name, age, hobby = 'coding' /* 结构赋值的默认值 */] = ['一碗周', 18]
// 交换两个变量的值
let a = 1
let b = 2
;[a, b] = [b, a]
console.log(a, b) // 2 1
// 对象的结构赋值
let { name: ObjName /* 解构赋值重命名 */, sex } = { name: '一碗周', sex: 1 }
// 函数参数的解构赋值
function bar({ name, age }) {
return name + age
}
bar({ name: '一碗周', age: 18 }) // 一碗周18
🫑 Symbol
Symbol 是ES2015中新增的一种数据类型,通过Symbol() 方法创建,可以传递一个字符串作为参数,用于描述该Symbol;通过Symbol() 方法创建的值都是唯一的,示例代码如下:
/**
* 语法
* Symbol([description])
* * description -> 是一个可选的描述信息
*/
// 创建一个 Symbol 类型的值
const mySymbol = Symbol()
console.log(mySymbol) // Symbol()
const myName = Symbol('一碗周')
console.log(typeof myName) // symbol
- Symbol.for() 方法,示例代码如下:
// Symbol.for('yy') 此API首先会在全局寻找Symbol.for('yy')这个变量,
// 如果有就会把当前这个Symbol赋值到b1中,如果没有就创建一个Symbol再赋值
let b1 = Symbol.for('yy')
let b2 = Symbol.for('yy')
console.log(b1) // Symbol(yy)
console.log(b2) // Symbol(yy)
console.log(b1 === b2) // true
🥕 Promise
Promise是ES2015中提供的一个异步解决方案,解决了回调地狱的问题。
通过Promise() 构造函数可以创建一个promise对象,每一个Promise对象都具有以下几种状态:
- Pending:初始状态,既不是成功,也不是失败状态。
- resolved:意味着操作成功完成。
- rejected:意味着操作失败。
状态的切换只有两种,分别是:
- pending -> resolved
- Pending -> rejected
一旦状态发生改变,就不会再次改变。
Promise实例中存在要给then方法,允许我们在Promise实例中链式调用,每个then方法还会返回一个Promise实例,如下图所示:
示例代码如下:
new Promise((resolve, reject) => {
console.log('我是第一个Promise中的log')
resolve()
})
.then(() => {
console.log('我是第一个then中的log')
})
.then(() => {
console.log('我是第二个then中的log,但是我出现了异常')
throw new Error('Error')
})
.then(() => {
console.log('我是第三个then中的第一个回调的log,但是我不会执行,因为我上面出现了异常')
}, () => {
console.log('我是第三个then中的第二个回调的log,我执行了')
})
.then(() => {
console.log('我是第四个then中的log,我可以正常执行')
})
/* 执行结果如下
我是第一个Promise中的log
我是第一个then中的log
我是第二个then中的log,但是我出现了异常
我是第三个then中的第二个回调的log,我执行了
我是第四个then中的log,我可以正常执行
*/
有关Promise
的一些方法如下:
Promise.prototype.then()
:它最多需要有两个参数:Promise的成功和失败情况的回调函数;Promise.prototype.catch()
:等于then
方法的第二个参数;Promise.all()
:将多个实例包装成一个新实例,返回全部实例状态变更后的结果数组(齐变更再返回)Promise.race()
:将多个实例包装成一个新实例,返回全部实例状态优先变更后的结果(先变更先返回)Promise.resolve()
:将对象转为Promise对象(等价于new Promise(resolve => resolve())
)Promise.reject()
:将对象转为状态为rejected
的Promise对象(等价于new Promise((resolve, reject) => reject())
)