ES6新特性
ES6,全称是 ECMAScript 6,也被称为 ECMAScript 2015,是 JavaScript 的一种标准,于 2015 年正式发布。ES6 是 JavaScript 新一代标准的缩写,引入了很多新的语法和特性,丰富了 JavaScript 的功能和表现力,提升了开发效率。
新特性
1 let和const
引入了块级作用域的变量声明方式,用于替代 var 关键字。
与var区别:不能重复声明,只会在作用域内生效,没有变量提升。
let a = 1 // 声明变量
const PI = 3.14 // 声明常量2 箭头函数
新的函数声明方式,可以更简洁地编写函数表达式。
// ES6 允许使用 => 定义函数//声明函数let fn = (a, b) => { return a + b}//调用函数console.log(fn(1, 2))箭头函数中 this 是静态的, this 始终指向函数声明时所在作用域下的 this 的值
function getName() { console.log(this.name)}
let getName2 = () => { console.log(this.name)}
// 设置 window对象 的 name 属性window.name = 'xxyyzz'const school = { name: 'qinghua',}
getName() // this 指向 window 输出 xxyyzzgetName2() // this 指向 window 输出 xxyyzz
getName.call(school) // 结果是qinghuagetName2.call(school) // 结果还是 xxyyzz不能作为构造实例化对象
let Person = (name, age) => { this.name = name this.age = age}let person = new Person('xxyyzz', 18)console.log(person)// 报错: Person is not a constructor不能使用 arguments 变量
let fn1 = () => { console.log(arguments)}fn1(1, 2, 3)// 报错: arguments is not defined简写
// 1. 只有一个参数省略括号let add = n => { return n + n}
// 2. 只有一个return省略花括号let pow = n => n * n
// 3. 返回对象简写const fn = uname => ({uname: uname})3 模板字符串
用反引号(“)来创建多行字符串和插入变量。
// 1. 变量const hello = 'hello'const world = 'world'console.log(`${hello} ${world}`) // hello world
// 2. 字符let str2 = `<ul> <li>1</li> <li>2</li> </ul>`console.log(str2)
// 3. 表达式let a = 3let b = 4let str3 = `${a + b}`console.log(str3)4 默认参数
在函数声明时可以为参数设置默认值。
function add(a, b, c = 10) { return a + b + c}let result = add(1, 2)
console.log(result) // 13
// 2. 可以与结构赋值结合function connect({host = '127.0.0.1', username, password, port}) { console.log(host) console.log(username) console.log(password) console.log(port)}
connect({ host: 'localhost', username: 'root', password: 'root', port: 3306,})5 解构赋值
可以通过解构语法从数组或对象中提取值并赋给变量。
// 1. 数组const F4 = ['xx', 'yy', 'zz', 'kk']let [x, y, z, k] = F4console.log(x) // xxconsole.log(y) // yyconsole.log(z) // zzconsole.log(k) // kk
// 2. 对象const zs = { name: '张三', age: 18, sing: function () { console.log('我会唱歌') },}
let {name, age, sing} = zs // 需要用大括号console.log(name) // 张三console.log(age) // 18console.log(sing) // Function
sing() // 我会唱歌
// 3. 多维解构const dog = { name: 'Gallagher', attr: { age: 13, birth: 'Pinocorni', },}
const { name, attr: {age, birth},} = dog
console.log(name) // Gallagherconsole.log(age) // 13console.log(birth) // Pinocorni6 类关键字class
引入了 class 关键字,可以更方便地创建基于原型的面向对象编程。
ES5中:
// 手机function Phone(brand, price) { this.brand = brand this.price = price}
// 添加方法Phone.prototype.call = function () { console.log('正在呼叫...')}
// 实例化对象let honor = new Phone('荣耀', 2499)console.log(honor)honor.call()ES6中:
class Phone { // 构造方法 constructor(brand, price) { // constructor 名字不能修改,是固定的 this.brand = brand this.price = price } // 添加方法,(方法必须使用该语法) call() { console.log('华为手机正在呼叫...') }}
// 实例化对象let honor = new Phone('华为', 2499)console.log(honor)honor.call()静态成员
// 类的静态成员class Phone { static name = 'nojiya' static change = function () { console.log('我可以改变你们') }}
let phoneSHI = new Phone()console.log(phoneSHI)console.log(phoneSHI.name) // undefinedconsole.log(Phone.name) // nojiyaconsole.log(Phone.change)类继承
// ES6中使用class实现类继承// 手机class Phone { constructor(brand, price) { this.brand = brand this.price = price } call() { console.log('正在呼叫...') }}
// 智能手机// extends关键字class SmartPhone extends Phone { constructor(brand, price, color, size) { super(brand, price) //super 关键字用于调用父类的构造函数或方法。 this.color = color this.size = size } photo() { console.log('正在拍照...') }}
// 测试let s = new SmartPhone('荣耀', 1399, '银色', '4.2inch')console.log(s)s.call()s.photo()class 中的 get 和 set
class Phone { get price() { console.log('price属性被读取了') return 'iloveyou' } set price(newVal) { console.log('price属性被修改了') }}
// 实例化对象let s = new Phone()console.log(s.price)
// 赋值s.price = 'free'7 Promise
用于处理异步操作的新标准,避免回调地狱的问题。可以返回新的Promise链式调用。
// 创建Promise对象const promise = new Promise((resolve, reject) => { setTimeout(() => { resolve('成功') })})
// Promise.thenpromise.then(value => { console.log(value)})
console.log(result)
// Promise.catchconst promise2 = new Promise((resolve, reject) => { setTimeout(() => { reject('出错啦!') }, 1000)})
promise2.catch(reason => { console.warn(reason)})8 模块化
引入了 import 和 export 关键字,提供了更好的模块化管理方式。
- 暴露:export
- 导入:import
9 扩展运算符...
用三个点(…)可以将数组或对象展开成分散的值。
const boys = ['张三', '李四', '王五']
// 声明一个函数function show() { console.log(arguments)}show(...boys) // ['张三', '李四', '王五']
// 案例:合并数组const arr1 = [1, 2, 3]const arr2 = [4, 5, 6]
const arr = [...arr1, ...arr2]console.log(arr) // [1, 2, 3, 4, 5, 6]10 简化对象声明
可以直接写属性名,而无需写键和值。
let name = '张三'let change = function () { console.log('这是一个方法')}const sch = { // 1. 定义对象的简写形式 // 2. 省略了属性值和冒号 name, // 旧版 name: name change, // 旧版 change: change // 3.方法前面省略了function关键字 improve() { // 旧版improve: function() { console.log('这是一个方法') },}console.log(sch)11 rest 参数
rest参数获取剩余的所有参数,只能放在最后,返回一个参数数组
function date1(...args) { console.log(args)}date1('2021-10-10', '2021-10-11', '2021-10-12') // 得到的是数组12 生成器函数
通过 function* 和 yield 关键字实现的一种可暂停和恢复执行的函数。
写法的特殊地方就是需要加个 * 星号,靠左,靠右,中间都行
function* gen() { console.log('hello generator')}
let iterator = gen()console.log(iterator)yield可以看成是函数代码的分隔符,通过next方法来控制执行
function* gen() { console.log('111') yield '我是1' // yield为函数代码的分隔符 console.log('222') yield '我是2' console.log('333') yield '我是3' console.log('444')}
let iterator = gen()console.log(iterator)iterator.next() // 111iterator.next() // 222iterator.next() // 333iterator.next() // 444生成器参考
function* gen(arg) { console.log(arg) let re1 = yield 111 console.log(re1) let re2 = yield 222 console.log(re2) let re3 = yield 333 console.log(re3)}
// 执行获取迭代器对象let iterator = gen('AAA')console.log(iterator.next())
// next方法可以传入实参console.log(iterator.next('BBB')) // 第二次调用传入的参数,将作为第一个yield语句的返回结果console.log(iterator.next('CCC')) // 第三次调用传入的参数,将作为第二个yield语句的返回结果console.log(iterator.next('DDD')) // 第四次调用传入的参数,将作为第三个yield语句的返回结果解决地狱回调
// 地狱回调setTimeout(() => { console.log(111) setTimeout(() => { console.log(222) setTimeout(() => { console.log(333) }, 3000) }, 2000)}, 1000)
// 解决后function one() { setTimeout(() => { console.log(111) iterator.next() // 执行下一个任务 }, 1000)}
function two() { setTimeout(() => { console.log(222) iterator.next() }, 2000)}
function three() { setTimeout(() => { console.log(333) iterator.next() }, 3000)}
// 定义生成器函数function* gen() { yield one() yield two() yield three()}
// 调用生成器函数let iterator = gen()iterator.next()13 Map和Set
新的数据结构,提供了更方便的数据存储和操作方式。
Map 键值对集合
let myMap = new Map()
// 添加键值对(元素)myMap.set('name', '张三')myMap.set('age', 18)
let key = { school: 'university',}myMap.set(key, ['清华大学', '北京大学'])console.log(myMap)
// 获取Map中的元素个数console.log(myMap.size)
// 删除元素myMap.delete('age')console.log(myMap)
// 获取元素console.log(myMap.get('name'))console.log(myMap.get(key))
// 判断Map中是否存在某个元素console.log(myMap.has('name'))console.log(myMap.has('age'))
// 遍历Mapfor (let v of myMap) { console.log(v)}
// 清空MapmyMap.clear()console.log(myMap)Set 不重复集合
let mySet = new Set()console.log(mySet)console.log(typeof mySet)
let mySet2 = new Set(['好事', '坏事', '大事', '好事']) // 自动去重console.log(mySet2)
// 元素个数console.log(mySet2.size)
// 添加元素mySet2.add('小事')console.log(mySet2)
// 删除元素mySet2.delete('坏事')console.log(mySet2)
// 检测是否有该元素console.log(mySet2.has('大事')) // 返回结果是boolean类型
// 清空setmySet2.clear()console.log(mySet2)
// 遍历Set: 集合实现了iterator接口,所以可以使用for...of进行遍历for (let item of mySet2) { console.log(item)}14 Symbol
ES6(ECMAScript 2015)引入了一种新的原始数据类型 Symbol。Symbol 是一种独一无二且不可变的数据类型,每个通过 Symbol 函数创建的 Symbol 值都是唯一的,即使符号名相同也不会相等。Symbol 主要用于对象属性的标识符,可以作为对象的属性名,用来解决属性名冲突的问题。
下面是 Symbol 的一些特点和用法:
-
独一无二性:每个 Symbol 值都是唯一的,不会与其他的 Symbol 值相等。这使得 Symbol 可以用作对象的属性名,保证属性的唯一性。
-
不可改变性:Symbol 是不可变的,一旦创建就不能修改其值。
-
Symbol 作为对象属性名:使用 Symbol 作为对象的属性名,可以确保属性不会被意外覆盖。可以通过 Symbol() 方法创建一个 Symbol 值,然后作为属性名定义在对象中。
-
内置 Symbol 值:ES6 提供了一些预定义好的 Symbol 值,如
Symbol.iterator、Symbol.toStringTag等,用于标识特定行为,可以在对象上使用这些 Symbol 值进行定制。 -
Symbol.for() 和 Symbol.keyFor():ES6 还提供了两个与全局 Symbol 相关的静态方法 Symbol.for() 和 Symbol.keyFor()。Symbol.for() 方法接收一个字符串作为参数,如果存在相同字符串的 Symbol 值则返回,否则新建一个;Symbol.keyFor() 方法则是返回与 Symbol 关联的键。
// 1. 创建Symbollet s = Symbol()console.log(s, typeof s) // Symbol() 'symbol'
// 2. 每一个都是独一无二的let s2 = Symbol('张三')let s3 = Symbol('张三')
console.log(s2, s3)console.log(s2 === s3) // false
// 3. Symbol.for 创建可以得出相同值let s4 = Symbol.for('李四')let s5 = Symbol.for('李四')
console.log(s4, s5)console.log(s4 === s5) // true
// 4. 作为对象属性let info = { name: '张三', [Symbol('age')]: 20, [Symbol('say')]: function () { console.log('我要说话了!') },}15 迭代器
ES6 引入了迭代器(Iterator)的概念,迭代器是一种能够让我们遍历数据结构的方法。通过迭代器,我们可以按照特定顺序逐个访问数据结构中的元素,而不必关心数据结构的具体实现细节。
下面是关于 ES6 迭代器的一些重要信息和特点:
-
迭代器协议:ES6 迭代器是基于迭代器协议(Iterator Protocol)实现的,在一个对象上部署了 Symbol.iterator 方法,该对象就被视为可迭代对象(iterable),可以通过迭代器进行遍历。
-
迭代器对象:迭代器对象必须具有一个 next() 方法,每次调用 next() 方法后都会返回一个包含 value 和 done 两个属性的对象,value 表示下一个元素的值,done 表示是否遍历结束。
-
可迭代对象:实现了迭代器协议的对象被称为可迭代对象,例如数组、字符串、Map、Set 和自定义对象等,它们可以通过 for…of 循环、展开运算符(…)、解构赋值等方式进行遍历。
-
Symbol.iterator 方法:可迭代对象都会具有一个 Symbol.iterator 方法,调用该方法会返回一个迭代器对象,从而实现迭代访问。
-
for…of 循环:ES6 引入的 for…of 循环可以遍历可迭代对象,自动调用迭代器的 next() 方法,简化了遍历操作。
-
内置数据结构:ES6 的内置数据结构如数组、Map、Set 等都实现了迭代器协议,因此可以直接使用 for…of 循环来遍历这些数据结构。
迭代器工作原理:
-
创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
-
第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。
-
第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。
-
不断调用指针对象的next方法,直到它指向数据结构的结束位置。
-
每一次调用next方法都会返回一个包含value和done两个属性的对象。其中,value属性是当前成员的值,done属性是一个布尔值,表示遍历是否结束。
// 1. for...ofconst arr = [1, 2, 3, 4, 5]for (let element of arr) { console.log(element) // 输出:1 2 3 4 5}
// 2. 迭代器const arr = [1, 2, 3, 4, 5]let iterator = arr[Symbol.iterator]()
console.log(iterator.next()) // { value: 1, done: false }console.log(iterator.next()) // { value: 2, done: false }console.log(iterator.next()) // { value: 3, done: false }console.log(iterator.next()) // { value: 4, done: false }console.log(iterator.next()) // { value: 5, done: false }console.log(iterator.next()) // { value: undefined, done: true }
// 3. 自定义迭代器// 声明一个对象const banji = { name: '终极一班', stus: ['xiaoming', 'xiaoning', 'xiaotian', 'knight'], [Symbol.iterator]() { // 索引变量 let index = 0 return { next: () => { if (index < this.stus.length) { // 构建一个yield返回值 const result = {value: this.stus[index], done: false} // 下标自增 index++ return result } // 返回结束标志 return {value: undefined, done: true} }, } },}
for (let v of banji) { console.log(v)}16 数值扩展
- Number.EPSILON 是JavaScript表示的最小精度, EPSILON 属性的值接近于 2.2204460492503131e-16
- 引入进制
- Number.isFinite()
- Number.isNaN()
- Number.parserInt()、Number.parseFloat(),将字符串转为整数(浮点数)
- Number.isInteger(),判断一个数是否为整数
- Math.trunc(),将数字的小数部分抹掉
- Math.sign(),判断一个数是正数、负数、还是零,返回:1,-1
// 1. EPSILON 属性的值接近于 2.2204460492503131e-16function equal(a, b) { if (Math.abs(a - b) < Number.EPSILON) { return true } else { return false }}console.log(0.1 + 0.2) // 0.30000000000004console.log(0.1 + 0.2 === 0.3) // falseconsole.log(equal(0.1 + 0.2, 0.3)) // true
// 2. 二进制、八进制、十进制、十六进制let b = 0b10let o = 0o10let d = 10let x = 0x10console.log(b, o, d, x) // 2 8 10 16
// 3. 判断极大数function isFinite(num) { return Number.isFinite(num)}console.log(isFinite(5)) // trueconsole.log(isFinite(5.0)) // trueconsole.log(isFinite(5.1)) // trueconsole.log(isFinite(Infinity)) // false
// 4. 判断NaNfunction isNaN(num) { return Number.isNaN(num)}console.log(isNaN(5)) // falseconsole.log(isNaN(NaN)) // true17 对象方法扩展
- Object.is 对象是否完全相等
- Object.assign 对象的合并
- Object.setPrototypeOf 设置原型对象
- Object.getPrototypeOf 获取原型对象
转化
并不是所有的浏览器都能向chrome一样都能识别ES6新特性,所以需要进行转换
# 安装工具: babel-cli babel-preset-env browserifynpm i babel-cli babel-preset-env browserify -Dnpx babel src/js -d dist/js --presets=babel-preset-envnpx browserify dist/js/app.js -o dist/bundle.js参考
赞助支持
如果这篇文章对你有帮助,欢迎赞助支持!
部分内容可能已过时
March7th