es2015是es6。es全称“ECMAScript”,是根据ECMA-262标准实现的通用脚本语言,而由2015年6月正式发布的版本,其正式名为ECMAScript2015(ES2015),因其是ECMAScript的第6个版本,因此可简称为es6。
本教程操作环境:windows7系统、ECMAScript 6版、Dell G3电脑。
“es”简介
es全称“ECMAScript”,是根据 ECMA-262 标准实现的通用脚本语言,ECMA-262 标准主要规定了这门语言的语法、类型、语句、关键字、保留字、操作符、对象等几个部分。每次看到 ES 后面跟着数字,是 ECMAScript 的不同版本。
es6全称ECMAScript6(ECMAScript的第6个版本),是于2015年6月正式发布的JavaScript语言的标准,正式名为ECMAScript 2015(ES2015)。它的目标是使得JavaScript语言可以用来编写复杂的大型应用程序,成为企业级开发语言。
ECMAScript 6 目前基本成为业界标准,它的普及速度比 ES5 要快很多,主要原因是现代浏览器对 ES6 的支持相当迅速,尤其是 Chrome 和 Firefox 浏览器,已经支持 ES6 中绝大多数的特性。
在此后ECMA Script每年发布一个大版本新增加一些重要特性,我们称之为ES6+。
本文主要总结了ES2015-ES2019的主要特性,一个学习前端的童鞋应该是常用且理解的一些特性。
Promise、Proxy、Object.assign等
Symbol、Set、Map等
PC浏览器对ES2015的支持情况
移动端浏览器对ES2015的支持情况
服务器对ES2015的支持情况,具体查看:https://node.green/
const [foo, bar, baz] = arr console.log(foo, bar, baz) const [, , baz] = arr console.log(baz) // 解构剩余的数组元素 // 只能在最后一个位置使用扩展运算符 const [foo, ...rest] = arr console.log(rest) // 解构时元素较少,按照顺序取元素 const [foo] = arr console.log(foo) // 解构时设置默认值 const [foo, bar, baz = 123, more = 'default value'] = arr console.log(bar, more)
const obj = { name: 'zce', age: 18 } // 变量名重复时,可以重命名和设置默认值 const name = 'tom' const { name: objName = 'jack' } = obj console.log(objName)
const name = 'tom' // 可以通过 ${} 插入表达式,表达式的执行结果将会输出到对应位置 const msg = `hey, ${name} --- ${1 + 2} ---- ${Math.random()}` console.log(msg)
const message = 'Error: foo is not defined.' console.log( // message.startsWith('Error') // message.endsWith('.') message.includes('foo') )
// 默认参数一定是在形参列表的最后 function foo (bar,enable = true) { console.log('foo invoked - enable: ') console.log(enable) } foo(false)
function foo (first, ...args) { console.log(args) } foo(1, 2, 3, 4)
const arr = ['foo', 'bar', 'baz'] // console.log( // arr[0], // arr[1], // arr[2], // ) // console.log.apply(console, arr) console.log(...arr)
插件:Fira Code字体将箭头画的更好看
const arr = [1, 2, 3, 4, 5, 6, 7] // arr.filter(function (item) { // return item % 2 // }) // 常用场景,回调函数 arr.filter(i => i % 2)
箭头函数的简写
function(value){return value} 等价于 value=>value
箭头函数的this指向
// 箭头函数与 this // 箭头函数不会改变 this 指向 const person = { name: 'tom', // sayHi: function () { // console.log(`hi, my name is ${this.name}`)//tom,this指向该函数调用者 // } sayHi: () => { console.log(`hi, my name is ${this.name}`) //undefined,this和sayHi()外面的函数this相同 }, sayHiAsync: function () { // const _this = this // setTimeout(function () { // console.log(_this.name) //这里的this为window,所以需要使用_this // }, 1000) console.log(this) setTimeout(() => { // console.log(this.name) //这里的this指向sayHiAsync里的this,即person console.log(this) }, 1000) } } person.sayHi() person.sayHiAsync()
const bar = '345' const obj = { foo: 123, // bar: bar // 属性名与变量名相同,可以省略 : bar bar, // method1: function () { // console.log('method111') // } // 方法可以省略 : function method1 () { console.log('method111') // 这种方法就是普通的函数,this 指向obj。 console.log(this) }, // Math.random(): 123 // 不允许,使用[]才行 // 通过 [] 让表达式的结果作为属性名 [bar]: 123 }
Object.assign是不完全的深拷贝?它究竟拷贝了多少东西?
获取不到obj中的get、set信息
const source1 = { a: 123, b: 123 } const source2 = { b: 789, d: 789 } const target = { a: 456, c: 456 } const result = Object.assign(target, source1, source2) console.log(target) console.log(result === target) //true,目标对象和返回值是一个对象
0 == false // => true 0 === false // => false +0 === -0 // => true NaN === NaN // => false Object.is(+0, -0) // => false Object.is(NaN, NaN) // => true
Proxy的作用
对Object属性变化进行监听
对比Object.defineProperty
参考笔记:https://gitee.com/ymcdhr/e-task/wikis/?sort_id=4053906
const obj = { foo: '123', bar: '456' } const proxy = new Proxy(obj, { get (target, property) { console.log('watch logic~') // Proxy中如果不写,默认调用了此方法 return Reflect.get(target, property) } })
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect
// console.log('name' in obj) // console.log(delete obj['age']) // console.log(Object.keys(obj)) console.log(Reflect.has(obj, 'name')) console.log(Reflect.deleteProperty(obj, 'age')) console.log(Reflect.ownKeys(obj))
// class 关键词 // function Person (name) { // this.name = name // } // Person.prototype.say = function () { // console.log(`hi, my name is ${this.name}`) // } class Person { // 构造函数 constructor (name) { this.name = name } // 成员变量 age = 18 // 成员函数 say () { console.log(`hi, my name is ${this.name}`) } } const p = new Person('tom') p.say()
// static 方法 class Person { constructor (name) { this.name = name } say () { console.log(`hi, my name is ${this.name}`) } static create (name) { return new Person(name) } } const tom = Person.create('tom') tom.say()
class Person { constructor (name) { this.name = name } say () { console.log(`hi, my name is ${this.name}`) } } class Student extends Person { constructor (name, number) { super(name) // 调用父类构造函数,否则name就没有赋值(重要) this.number = number } hello () { super.say() // 调用父类成员 console.log(`my school number is ${this.number}`) } } const s = new Student('jack', '100') s.hello()
Set 没有重复元素的数组集合
常用的成员方法
const s = new Set() s.add(1).add(2).add(3).add(4).add(2) // console.log(s) // s.forEach(i => console.log(i)) //forEach、for...of 都可以用来遍历Set // for (let i of s) { // console.log(i) // } // console.log(s.size) // console.log(s.has(100)) // console.log(s.delete(3)) // console.log(s) // s.clear() // console.log(s)
常用来数组去重
// 应用场景:数组去重 const arr = [1, 2, 1, 3, 4, 1] const result1 = Array.from(new Set(arr)) const result2 = [...new Set(arr)] console.log(result1,result2)
Map 能使用复杂结构作为属性的对象集合
以前的对象存储对象属性时,会将复杂数据转换成字符串(toString()方法),如下:
const obj = {} obj[true] = 'value' obj[123] = 'value' obj[{ a: 1 }] = 'value' console.log(Object.keys(obj)) //0: "123" //1: "true" //2: "[object Object]"
使用Map可以存储复杂数据作为对象属性,常用的方法有如下:
const m = new Map() const tom = { name: 'tom' } m.set(tom, 90) console.log(m) console.log(m.get(tom)) // m.has() // m.delete() // m.clear() // forEach可以遍历Map中的item m.forEach((value, key) => { console.log(value, key) })
一个全新的基础数据类型,每次创建都是独一无二的值
let s = Symbol(); typeof s // "symbol" let s1 = Symbol('foo'); let s2 = Symbol('foo'); s1 === s2 // false // for方法是创建的一样的值,参数会自动转换成字符串 let s3 = Symbol.for('foo'); let s4 = Symbol.for('foo'); s3 === s4 // true
可以转换为字符串,通过description(ES2019提供的方法)
let s1 = Symbol('foo'); let s2 = Symbol('foo'); s1 // Symbol(foo) s2 // Symbol(foo) s1 === s2 // false s1.toString() // "Symbol(foo)" s2.toString() // "Symbol(foo)" s1.description // "foo" // ES2019提供的方法
可以作为对象的属性名,可以避免同名冲突
const obj = {} obj[Symbol()] = '123' obj[Symbol()] = '456' console.log(obj) //Symbol(): "123" //Symbol(): "456"
使用 Symbol 值定义属性时,Symbol 值必须放在方括号之中,而且不能使用点运算符
let s = Symbol(); // 第一种写法 let a = {}; a[s] = 'Hello!'; // 第二种写法 let a = { [s]: 'Hello!' }; // 以上写法都得到同样结果 a[s] // "Hello!"
可以作为对象的私有成员,不能在外部直接访问(因为每次访问都不一样),只能通过内部this访问
// 案例2:Symbol 模拟实现私有成员 // a.js ====================================== const name = Symbol() const person = { [name]: 'zce', say () { console.log(this[name]) } } // 只对外暴露 person // b.js ======================================= // 由于无法创建出一样的 Symbol 值, // 所以无法直接访问到 person 中的「私有」成员 // person[Symbol()] person.say()
注意:for…in、Obeject.keys、Json.stringify都无法在Symbol上使用
使用:Object.getOwnPropertySymbols,替代Obeject.keys方法用于Symbol
以前的 for…in 遍历键值对,forEach 存在局限性
可以用使用break终止遍历,forEach不能跳出循环
可以遍历Array数组、Set和Map对象
普通对象不能被直接 for…of 遍历,因为它没有Symbol.iterator属性
对象(Object)之所以没有默认部署 Iterator 接口,是因为对象的哪个属性先遍历,哪个属性后遍历是不确定的,需要开发者手动指定。
所有可以使用 for…of 的对象都需要具有Symbol.iterator属性
// for...of 循环 const arr = [100, 200, 300, 400] // for...of 循环可以替代 数组对象的 forEach 方法 但可以使用break跳出循环 arr.forEach(item => { console.log(item) }) for (const item of arr) { console.log(item) if (item > 100) { break } } // forEach 无法跳出循环,必须使用 some 或者 every 方法 // arr.forEach() // 不能跳出循环 // arr.some() // arr.every() // 遍历 Set 与遍历数组相同 const s = new Set(['foo', 'bar']) for (const item of s) { console.log(item) } // 遍历 Map 可以配合数组结构语法,直接获取键值 const m = new Map() m.set('foo', '123') m.set('bar', '345') for (const [key, value] of m) { console.log(key, value) } // 普通对象不能被直接 for...of 遍历 const obj = { foo: 123, bar: 456 } for (const item of obj) { console.log(item) }
具有 Symbol.iterator 属性的数据结构
Array、Map、Set、String、TypedArray、函数的 arguments 对象、NodeList 对象
iterator 的遍历过程是这样的。
使对象能够使用 for…of
const obj = { // 使用计算属性,用[]存表达式属性名 // 1、Iterable,对象必须要有一个Symbol.iterator属性 [Symbol.iterator]: function () { return { // 2、Iterator,返回的对象有一个next()方法 next: function () { // 3、IterationResult,next()方法返回一个对象 return { value: 'zce', done: true } } } } } for (const item of obj) { console.log('循环体', item) }
使对象能够使用 for…of,完整的代码
const obj = { store: ['foo', 'bar', 'baz'], [Symbol.iterator]: function () { let index = 0 const self = this return { next: function () { const result = { value: self.store[index], done: index >= self.store.length } index++ return result } } } } for (const item of obj) { console.log('循环体', item) }
迭代器的另外一个主要用途:迭代器模式
数组的includes方法
// Array.prototype.includes ----------------------------------- const arr = ['foo', 1, NaN, false] // 找到返回元素下标 console.log(arr.indexOf('foo')) // 找不到返回 -1 console.log(arr.indexOf('bar')) // 无法找到数组中的 NaN console.log(arr.indexOf(NaN)) // 直接返回是否存在指定元素 console.log(arr.includes('foo')) // 能够查找 NaN console.log(arr.includes(NaN))
指数运算符
// 指数运算符 --------------------------------------------------- console.log(Math.pow(2, 10)) console.log(2 ** 10)
Object.values —— 类似Object.keys,返回对象的值数组
Object.entries —— 以数组的形式返回对象中的键值对,结合for…of可以遍历obj
const obj = { foo: 'value1', bar: 'value2' } // Object.values ----------------------------------------------------------- console.log(Object.values(obj)) // Object.entries ---------------------------------------------------------- console.log(Object.entries(obj)) // 比iterator 更简单,直接先将obj转换成数组,再使用 for...of for (const [key, value] of Object.entries(obj)) { console.log(key, value) } console.log(new Map(Object.entries(obj)))
Object.getOwnPropertyDescriptors —— 获取对象属性的完整信息,主要配合ES5的get、set使用
Object.assign 获取不到set、get信息
const p1 = { firstName: 'Lei', lastName: 'Wang', get fullName () { return this.firstName + ' ' + this.lastName } } // console.log(p1.fullName) // const p2 = Object.assign({}, p1) // p2.firstName = 'zce' // console.log(p2) const descriptors = Object.getOwnPropertyDescriptors(p1) // console.log(descriptors) const p2 = Object.defineProperties({}, descriptors) p2.firstName = 'zce' console.log(p2.fullName)
String.prototype.padStart / String.prototype.padEnd
const books = { html: 5, css: 16, javascript: 128 } // for (const [name, count] of Object.entries(books)) { // console.log(name, count) // } for (const [name, count] of Object.entries(books)) { console.log(`${name.padEnd(16, '-')}|${count.toString().padStart(3, '0')}`) }
const arr = [ 100, 200, 300, 400, ] const arr = [ 100, 200, 300 ]
来自于ES2017标准;async、await能够更方便的进行异步编程,且通常需要成对使用;
1、async、await相对于generate函数升级提升的地方:
2、async、await的返回值
1、async函数返回一个 Promise 对象。
2、async函数内部return语句返回的值,会成为then方法回调函数的参数。
async function f() { return 'hello world'; } f().then(v => console.log(v)) // "hello world"
3、await 后面的参数
4、错误处理方法
如果await后面的promise异步操作出错,那么等同于async函数返回的 Promise 对象被reject。最好把await命令放在try…catch代码块中
async function f() { await new Promise(function (resolve, reject) { throw new Error('出错了'); }); } f() .then(v => console.log(v)) .catch(e => console.log(e)) async function myFunction() { try { await somethingThatReturnsAPromise(); } catch (err) { console.log(err); } } // 另一种写法 async function myFunction() { await somethingThatReturnsAPromise() .catch(function (err) { console.log(err); }); }
5、并发/循环异步请求的处理
(1)如果是串行执行异步请求,需要同步等待,会比较耗时;
let foo = await getFoo(); let bar = await getBar(); // 1、循环里面的串行执行: async function dbFuc(db) { let docs = [{}, {}, {}]; for (let doc of docs) { await db.post(doc); } } // 2、错误的串行执行:?why?思考?forEach里面的async应该是异步同时执行的,没有await? function dbFuc(db) { //这里不需要 async let docs = [{}, {}, {}]; // 可能得到错误结果 docs.forEach(async function (doc) { await db.post(doc); }); }
(2)并行执行——等待所有响应,再执行下一个步骤;
async function dbFuc(db) { let docs = [{}, {}, {}]; let promises = docs.map((doc) => db.post(doc)); let results = await Promise.all(promises); console.log(results); } // 或者使用下面的写法 async function dbFuc(db) { let docs = [{}, {}, {}]; let promises = docs.map((doc) => db.post(doc)); let results = []; for (let promise of promises) { results.push(await promise); } console.log(results); }
(3)并行执行——不等待所有响应,回来一个回调一个;
// 可以不要在for里面await;也不要写成串行的回调; // 是在for里面写异步方法的调用?例如: let docs = [{}, {}, {}]; for (let doc of docs) { db.post(doc).then((res)=>{}); }
6、async、await原理(利用generator实现async、await)
async、await底层封装起来了看不见代码实现
可以利用iterator或者generator函数,进行封装实现;参考代码:(未完待续)
6+1 种原始数据类型 + bigInt(下个版本)
null
undefined
number
string
boolean
Symbol(ES2015)
BigInt(stage-4,下个版本出标准化)
【相关推荐:javascript视频教程、编程视频】
以上是es2015就是es6吗的详细内容。更多信息请关注PHP中文网其他相关文章!