ES6
ES 全称 EcmaScript,是脚本语言的规范,而平时经常编写的 JavaScript,是 EcmaScript 的一种实现,
所以,ES 新特性其实指的就是 JavaScript 的新特性。 // ES 6-11,指的是 ES 的几个版本
为什么要学习新特性 ?
- 语法简洁、功能丰富
- 框架开发应用
- 前端开发职位要求
EcmaScript 概述
ECMAScript 是由 Ecma 国际通过 ECMA-262 标准化的脚本程序设计语言。
ECMA( European Computer Manufacturers Association )中文名称为欧洲计算机制造商协会,这个组织的目标是评估、开发和认可电信和计算机标准。1994 年后该组织改名为 Ecma 国际。
- Ecma 国际制定了许多标准,而 ECMA-262 只是其中的一个:
(1)ECMA-262( ECMAScript )历史版本: // 从 ES6 开始,每年发布一个版本,版本号比年份最后一位大 1
- 第 1 版 — 1997 年:制定了语言的基本规范
- 第 2 版 — 1998 年:较小改动
- 第 3 版 — 1999 年:引入正则、异常处理、格式化输出等。IE 开始支持
- 第 4 版 — 2007 年:过于激进,未发布
- 第 5 版 — 2009 年:引入严格模式、JSON,扩展对象、数组、原型、字符串、日期方法
- 第 6 版 — 2015 年:模块化、面向对象语法、Promise、箭头函数、let、const、数组解构赋值等等
- 第 7 版 — 2016 年:幂运算符、数组扩展、Async/await 关键字
- 第 8 版 — 2017 年:Async/await、字符串扩展
- 第 9 版 — 2018 年:对象解构赋值、正则扩展
- 第 10 版 — 2019 年:扩展对象、数组方法
- 第 11 版 — 2020 年:链式操作、动态导入等
- ...
(2)谁在维护 ECMA-262
TC39( Technical Committee 39 )是推进 ECMAScript 发展的委员会。其会员都是公司( 其中主要是浏览器厂商,有苹果、谷歌、微软、因特尔等 )。TC39 定期召开会议,会议由会员公司的代表与特邀专家出席。
(3)为什么要学习 ES6
- ES6 的版本变动内容最多,具有里程碑意义
- ES6 加入许多新的语法特性,编程实现更简单、高效
- ES6 是前端发展趋势,就业必备技能
(4)ES6 兼容性:http://kangax.github.io/compat-table/es6
ES6 新特性
[1] let 关键字:声明局部变量 // 以后声明变量,使用 let 就对了
1 2 3 4 5 6 |
<script> let a; // 单个声明 let b,c,d; // 批量声明 let e = 100; // 单个声明,并赋值 let f = 200,g = 'test'; // 批量声明,并赋值 </script> |
特性:
- 不允许重复声明
1234 <script>let dog = '小狗';let dog = '大狗'; // Uncaught SyntaxError: Identifier 'dog' has already been declared</script>
- 块级作用域( 局部变量 )
1234567 <script>{let cat = "猫";console.log(cat); // 猫}console.log(cat); // index.html:15 Uncaught ReferenceError: cat is not defined</script>
- 不存在变量提升
1234567 <script>console.log(dog); // undefinedconsole.log(cat); // Uncaught ReferenceError: Cannot access 'cat' before initializationvar dog = "狗"; // 存在声明提升,输出变量的默认值let cat = "猫"; // 不存在声明提升</script>
- 不影响作用域链
123456789 <script>{let cat = "猫";function fn(){console.log(cat); // 猫}fn();}</script>
[2] const 关键字:声明常量 // 通常,声明对象类型使用 const,非对象类型声明选择 let
1 2 3 4 |
<script> const DOG = '狗'; console.log(DOG) </script> |
特性:
- 声明必须赋初始值
1234 <script>const DOG;console.log(DOG); // Uncaught SyntaxError: Missing initializer in const declaration</script>
- 常量的标识符一般大写( 纯属习惯 )
- 常量的值不允许修改
123456 <script>const DOG = "狗";console.log(DOG); // 狗DOG = "大狗";console.log(DOG); // Uncaught TypeError: Assignment to constant variable.</script>
- 不允许重复声明,同 let
- 块级作用域( 局部变量 ),同 let
- 对于数组和对象的元素进行修改,不算做对常量的修改,不会报错( 因为地址没有发生变化 )
123456 <script>const arr = [1,2,3]console.log(arr); // [1, 2, 3]arr.push(4);console.log(arr); // [1, 2, 3, 4]</script>
[3] 变量和对象的解构赋值 // 频繁使用对象方法、数组元素,就可以使用解构赋值形式
什么是解构赋值?ES6 允许按照一定模式,从数组和对象中提取值,然后对变量进行赋值,这被称为“解构赋值”。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<script> // 数组的解构赋值 let [a,b,c] = ['大哥','二哥','三哥']; console.log(a); // 大哥 console.log(b); // 二哥 console.log(c); // 三哥 // 对象的解构赋值 let {name,run} = { name:"小明", age:10, run(){ console.log('跑步'); } } console.log(name); // 小明 run(); // 跑步 </script> |
[4] 模板字符串:声明自带格式的字符串 // 当遇到字符串和变量拼接的时候,可以使用模板字符串
模板字符串,是加强版的字符串,用反引号(
)表示,其特点为:
- 自带格式,字符串中可用出现换行
- 变量拼接,可用使用 ${ x } 的形式引用变量
12345678910 <script>let str1 = `字符串`;let str2 = `字符串`;console.log(str1); // 字符串console.log(str2); // (自带格式)let str3 = `这是一个${str1}`;console.log(str3); // 这是一个字符串</script>
[5] 简化对象和函数写法
ES6 允许在大括号里,直接写入变量和函数,作为对象的属性和方法,这样的写法更为简洁。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<script> let name = "小明"; let sing = function(){ console.log('唱歌'); } let obj = { // 完整写法 // name:name, // sing:sing, // 简化写法 name, sing, age:10, // 方法声明(简化) run(){ console.log('跑步'); } } console.log(obj.name); // 小明 obj.sing(); // 唱歌 obj.run(); // 跑步 </script> |
[6] 箭头函数:简化函数写法
ES6 允许使用箭头( => )来定义函数,箭头函数提供了一种更为简洁的函数书写方式,多用于匿名函数的定义。
1 2 3 4 5 6 7 8 9 10 11 |
<script> function func1() { console.log('方法1'); } func1(); // 方法1 // ES6写法 let func2 = () => { console.log('方法2') } func2(); // 方法2 </script> |
其特点为:
- 箭头函数不能作为构造函数实例化;
- 不能使用 arguments;
- 如果形参只有一个,小括号可以省略;
- 如果函数体只有一条语句,花括号也可以省略,函数的返回值为该条语句的执行结果;
1234567891011 <script>let func3 = function (a, b) {return a + b;}console.log(func3(10, 20)); // 30// ES6 写法let func4 = (a, b) => {return a + b;}console.log(func4(20, 50)); // 70</script>
- 箭头函数的 this 是静态的,始终指向声明时所在作用域下的 this 值;
1234567891011121314151617181920212223242526 <body><div id="sec1" style="width:100px;height: 100px;background: blue;"></div><div id="sec2" style="width:100px;height: 100px;background: blue;"></div><script>// 效果:点击 div#sec,2秒后颜色变为粉色(pink)let sec1 = document.getElementById('sec1');let sec2 = document.getElementById('sec2');// 传统写法sec1.addEventListener('click',function(){let that = this;setTimeout(function(){// 报错// this.style.background = "pink"; // Uncaught TypeError: Cannot set properties of undefined (setting 'background')// 解决that.style.background = "pink";},2000)})// ES6 写法sec2.addEventListener('click',function(){setTimeout(() => {this.style.background = "red";},2000)})</script></body>
[7] ES6 中函数参数的默认值:给函数的参数设置默认值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<script> // 默认值 function func(a,b,c = 10){ return a + b + c; } console.log(func(1,2)); // 13 // 与解构赋值配合使用 function connect({host="127.0.0.1",username,password,port}){ console.log(host); // 127.0.0.1 console.log(username); // root console.log(password); // root console.log(port); // 8080 } connect({ username:'root', password:'root', port:8080 }) </script> |
[8] rest 参数:获取实参( 实际上是函数的剩余参数 ) // ES6 rest 参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<script> let func1 = function () { console.log(arguments) // Arguments(3) ['大哥', '二哥', '三哥', callee: ƒ, Symbol(Symbol.iterator): ƒ] // Rest 参数简化了使用 arguments 获取多余参数的方法 var args = Array.prototype.slice.call(arguments); console.log(args); // ['大哥', '二哥', '三哥'] } func1("大哥", "二哥", "三哥"); // ES6引入了rest参数( ...args ),rest参数必须放在最后,否则会报错 let func2 = function (...args) { console.log(args); // ['大哥', '二哥', '三哥'] } func2("大哥", "二哥", "三哥"); let func3 = function (a,b,...args) { console.log(a); // 大哥 console.log(args); // ['三哥'] } func3("大哥", "二哥", "三哥"); </script> |
[9] 扩展运算符:将一个数组转化为用逗号分隔的参数序列
扩展运算符( ... ),好比 rest 参数的逆运算,将一个数组转化为用逗号分隔的参数序列,对数组进行解包。
123456789101112131415161718192021222324252627 <script>let arr = ['大哥','二哥','三哥'];let func = function (a, b, ...args) {console.log(a);console.log(args);}func(...arr);// 功能:数组合并let arr1 = [1,2];let arr2 = [3,4];// 传统方式let arr3 = arr1.concat(arr2);console.log(arr3); // [1,2,3,4]// 使用扩展运算符let arr4 = [...arr1,...arr2];console.log(arr4); // [1,2,3,4]</script><script>let func = function(){console.log(arguments); // 伪数组 // Arguments(3) ['大哥', '二哥', '三哥', callee: ƒ, Symbol(Symbol.iterator): ƒ]// 将伪数组转化为真正的数组console.log([...arguments]); // ['大哥', '二哥', '三哥']}func('大哥','二哥','三哥');</script>
[10] Symbol:表示独一无二的值 // Symbol 内置值的使用( 了解 )
ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值。它是 JS 的第 7 种数据类型,一种类似于字符串的数据类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<script> // 创建Symbol - 使用函数 Symbol() 创建 // 方式1: let s1 = Symbol(); // 说明:这是一个随机的值 console.log(s1,typeof s1); // Symbol() 'symbol' let s2 = Symbol('只是一个标识'); // Symbol(只是一个标识) console.log(s2); let s3 = Symbol('只是一个标识'); // Symbol(只是一个标识) console.log(s3 == s2); // false // 方式2: let s4 = Symbol.for('只是一个标识'); console.log(s4,typeof s4); // Symbol(只是一个标识) 'symbol' let s5 = Symbol.for('只是一个标识'); console.log(s5 == s4); // true </script> |
其特点为:
- Symbol 的值是唯一的,用来解决命名冲突的问题;
12345678910111213141516171819202122232425 <script>// Symbol 的主要应用场景是给对象添加独一无二的属性和方法const game = {name:'游戏名',up(){console.log('向上')},down(){console.log('向下')}}// 把它作为一个唯一的值,用来解决命名冲突的问题let method = {up:Symbol(),down:Symbol()}game[method.up] = function(){console.log('upup')}game[method.down] = function(){console.log('down')}game.up(); // 向上game[method.up](); // upup</script>
- Symbol 的值不能与其他数据进行计算;
123456 <script>// Symbol 的值不能与其他数据类型进行计算let s6 = Symbol();// console.log(s6 + 100); // Uncaught TypeError: Cannot convert a Symbol value to a number// console.log(s6 + 'test'); // Uncaught TypeError: Cannot convert a Symbol value to a string</script>
- Symbol 定义的对象属性不能使用 for ... in 循环遍历,但是可以使用 Reflect.ownKeys 来获取对象的所有键名;
- Symbol 的内置值:除了使用自己定义的 Symbol 值外,ES6 还提供了 11 个 内置的 Symbol 值,指向语言内部使用的方法,可以称这些方法为魔术方法,因为它们会在特定的场景下自动执行
说明:Symbol 内置值的使用,都是作为某个对象类型的属性去使用
1234567891011 <script>class Person{static [Symbol.hasInstance](param){console.log(param); // {name: '对象'},可以作为一个参数被传递进来console.log('进行类型检测了')}}let obj = {name:'对象'};// 当进行类型检测的时候就会被触发obj instanceof Person; // 进行类型检测了</script>
[11] 迭代器:用来遍历集合、数组等
遍历器( Iterator )就是一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。
任何数据结构只要部署 Iterator 接口,就可以完成遍历操作。
ES6 创造了一种新的遍历命令 for ... of 循环,Iterator 接口主要供 for ... of 消费;
原生具备 Iterator 接口的数据( 可以使用 for ... of 遍历 )有:
- Array
- Arguments
- Set
- Map
- String
- TypeArray
- NodeList
工作原理:
12345678910111213141516 <script>const arr = ['唐僧','孙悟空','猪八戒','沙僧'];for(let v of arr){console.log(v); // 依次打印:唐僧 孙悟空 猪八戒 沙僧}for(let i in arr){console.log(i); // 依次打印:0 1 2 3}let iterator = arr[Symbol.iterator]();console.log(iterator.next()); // {value: '唐僧', done: false}console.log(iterator.next()); // {value: '孙悟空', done: false}console.log(iterator.next()); // {value: '猪八戒', done: false}console.log(iterator.next()); // {value: '沙僧', done: false}console.log(iterator.next()); // {value: undefined, done: true}</script>
- 创建一个指针对象,指向当前数据结构的起始位置;
- 第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员;
- 接下来不断调用 next 方法,指针一直向后移动,直到指向最后一个成员;
- 每调用 next 方法,返回一个包含 value 和 done 属性的对象。
应用场景:需要自定义遍历数据的时候,要想到迭代器。
123456789101112131415161718192021222324252627282930 <script>let obj = {name: '一班',member: ['小明', '小红', '小白'],// 自定义遍历对象[Symbol.iterator]: function () {let index = 0;let that = this;return {next: function () {if (index < that.member.length) {const result = {value: that.member[index],done: false}index++;return result;}else{return {value:undefined,done:true}}}}}}// 自定义遍历对象 — 要求:输出member中的元素for (let v of obj) {console.log(v);}</script>
[12] 生成器:一种异步编程解决方案
生成器函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完成不同。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
<script> // 传统函数 function gen1(){ console.log(111); console.log(222); console.log(333); } gen1(); // 一次打印 // 生成器函数:在function和函数名之间加一个 * function * gen2(){ console.log(111); console.log(222); console.log(333); } // gen(); // 无法调用 // 其返回值实际是一个迭代器 let iterator2 = gen2(); iterator2.next(); // 可以调用 // 同时,可以搭配yield使用:yield 函数代码的分隔符 function * gen3(){ console.log(111); yield '片段1' console.log(222); yield '片段2' console.log(333); yield '片段3' } let iterator3 = gen3(); console.log(iterator3.next()) // 执行片段1部分:111 {value: '片段1', done: false} // ... // 因为是一个迭代器,因此可以使用 for of 遍历 for(let v of gen3()){ console.log(v) } </script> |
生成器函数的参数传递:
123456789101112131415 <script>function* gen(arg) {console.log(arg);let one = yield 111;console.log(one);let two = yield 222;console.log(two);let three = yield 333;console.log(three);}let iterator = gen("AAA");console.log(iterator.next()); // 会执行yield 111;// next()方法是可以传入参数的,传入的参数作为第一条(上一条)语句yield 111的返回console.log(iterator.next("BBB")); // 会执行yield 222; console.log(iterator.next("CCC")); // 会执行yield 333; console.log(iterator.next("DDD")); // 继续往后走,未定义;</script>// 代码示例:
123456789101112131415161718192021222324252627282930313233343536 <script>// 异步编程 文件操作 网络操作(ajax,request) 数据库操作// 需求:1s后控制台输出111 再过2s后控制台输出222 再过3s后控制台输出333// 一种做法:回调地狱// 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();}, 1000)}function three() {setTimeout(() => {console.log(333);iterator.next();}, 1000)}function* gen() {yield one();yield two();yield three();}// 调用生成器函数let iterator = gen(); iterator.next();</script>// 代码示例:
123456789101112131415161718192021222324252627 <script>// 模拟获取: 用户数据 订单数据 商品数据function getUsers() {setTimeout(() => {let data = "用户数据";// 第二次调用next,传入参数,作为第一个的返回值 iterator.next(data); // 这里将data传入}, 1000);}function getOrders() {setTimeout(() => {let data = "订单数据";iterator.next(data); // 这里将data传入}, 1000);}function getGoods() {setTimeout(() => {let data = "商品数据"; iterator.next(data); // 这里将data传入}, 1000);}function* gen() {let users = yield getUsers(); console.log(users);let orders = yield getOrders(); console.log(orders);let goods = yield getGoods(); console.log(goods);}let iterator = gen();iterator.next();</script>
[13] Promise:非常强大的一步编程的新解决方案
Promise 是 ES6 引入的异步编程的新解决方案。
语法上 Promise 是一个构造函数,用来封装异步操作并可以获取成功或者失败的结果。
- Promise 构造函数: Promise (excutor) {}
12345678910111213141516171819 <script>// Promise 对象的三种状态:初始化、成功、失败// 初始化:实例化Promise对象let p = new Promise(function(resolve,reject){let data = 123;// resolve(data); // 当使用resolve返回时,为成功状态,可以使用then方法的第一个函数接收数据reject('出错了!') // 当使用reject返回时,为失败状态,可以使用then方法的第二个函数接收,或者使用.catch方法接收})// then 方法p.then(function(value){console.log(value)},function(reason){console.log(reason) // 出错了!})// catch 方法,一个语法糖,用起来更简洁一些p.catch(function(reason){console.log(reason) // // 出错了!})</script>
代码示例:使用 Promise 封装读取文件
12345678910111213141516171819202122232425 let fs = require('fs');// Nodejs 常规写法fs.readFile('./index.html', (err, data) => {if (err) {return;}console.log(data.toString())})// Nodejs 使用 Primise 封装写法let p = new Promise((resolve, reject) => {fs.readFile('./index.html', (err, data) => {if (err) {reject(err)}resolve(data)})})p.then(value => {console.log(value.toString())}).catch((err) => {console.log(err)})
- Promise.prototype.then 方法的链式调用
12345678910111213141516171819202122232425262728293031 <script>// 创建 Promise 对象const p = new Promise((resolve, reject) => {setTimeout(() => {resolve("用户数据");}, 1000);});// 调用then方法,then方法的返回结果是promise对象, // 对象的状态有回调函数的结果决定;const result = p.then(value => {console.log(value);// 1、如果回调函数中返回的结果是 非promise 类型的数据, // 状态为成功,返回值为对象的成功值resolved// [[PromiseStatus]]:"resolved"// [[PromiseValue]]:123// return 123;// 2、如果...是promise类型的数据// 此Promise对象的状态决定上面Promise对象p的状态// return new Promise((resolve,reject)=>{// // resolve("ok"); // resolved// reject("ok"); // rejected// });// 3、抛出错误// throw new Error("失败啦!");// 状态:rejected// value:失败啦!}, reason => {console.error(reason);})// 链式调用// then里面两个函数参数,可以只写一个 p.then(value=>{},reason=>{}).then(value=>{},reason=>{});console.log(result);</script>代码示例:
12345678910111213141516171819202122232425262728293031323334353637 // 1、引入 fs 模块const fs = require("fs");// 2、调用方法,读取文件 - 回调地狱写法// fs.readFile("resources/text.txt", (err, data1) => {// fs.readFile("resources/test1.txt", (err, data2) => {// fs.readFile("resources/test2.txt", (err, data3) => {// let result = data1 + data2 + data3;// console.log(result);// });// });// });fs.readFile("resources/test2.txt", (err, data3) => {let result = data1 + data2 + data3;console.log(result);});// 3、使用Promise实现 - Promise 写法const p = new Promise((resolve, reject) => {fs.readFile("resources/text.txt", (err, data) => {resolve(data);});});p.then(value => {return new Promise((resolve, reject) => {fs.readFile("resources/test1.txt", (err, data) => {resolve([value, data]);});})}).then(value => {return new Promise((resolve, reject) => {fs.readFile("resources/test2.txt", (err, data) => { // 存入数组value.push(data);resolve(value);});})}).then(value => {console.log(value.join("\r\n"));})
[14] Set 集合:类似数组,但元素不重复的集合
ES6 提供了一种新的数据结构 Set( 集合 ),它类似于数组,但成员的值都是唯一的( 没有重复 )。
集合实现了 Iterator 接口,因此,可以使用 “ 扩展运算符 ” 和 “ for ... of ”。
集合的属性和方法有:
- size 属性,返回集合的元素个数;
- add() 方法,增加一个新元素,返回当前集合;
- delete() 方法,删除一个元素,返回 boolean 值;
- has() 方法,检测集合中是否包含某个元素,返回 boolean 值;
- clear() 方法,清空集合,返回 undefined;
12345678910111213141516171819202122 <script>let s = new Set();console.log(s,typeof s); // Set(0) {size: 0} 'object'let s1 = new Set(['大哥','二哥','三哥','三哥','大哥'])// 自动去重console.log(s1); // Set(3) {'大哥', '二哥', '三哥'}// 返回集合的元素个数console.log(s1.size); // 3// add() 增加一个新元素,返回当前集合console.log(s1.add('大姐')); // Set(4) {'大哥', '二哥', '三哥', '大姐'}// delete() 删除一个元素,返回boolean值console.log(s1.delete('二哥')); // trueconsole.log(s1); // Set(3) {'大哥', '三哥', '大姐'}console.log(s1.delete('二弟')) // false// has() 判断集合中是否包含某个元素,返回boolean值console.log(s1.has('大姐')); // trueconsole.log(s1.has('三弟')); // false// clear() 清空集合,返回undefinedconsole.log(s1.clear()) // undefinedconsole.log(s1) // Set(0) {size: 0}</script>
代码示例:
12345678910111213141516171819202122 <script>let arr = [1,2,3,4,5,6,5,4,3,2,1];// 数组去重let s = new Set(arr);console.log(s); // Set(6) {1, 2, 3, 4, 5, 6}// 转化为数组arr = [...s];console.log(arr); // [1, 2, 3, 4, 5, 6]// 取两个数组的交集let arr1 = [3,4,5,6,7,8,3,4,5]let s1 = new Set(arr1);let result1 = [];arr.filter(item => {if(s1.has(item)){result1.push(item);}})console.log(result1); // [3, 4, 5, 6]// 取两个数组的并集let result2 = [...new Set([...arr,...arr1])];console.log(result2); // [1, 2, 3, 4, 5, 6, 7, 8]</script>
[15] Map 集合:键值对集合 — 升级版的“对象”
ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合。
但是,“键”的范围并不局限于字符串,各种类型的值( 包括对象 )都可以作为键。
Map 集合也实现了 Iterator 接口,所以,可以使用 “ 扩展运算符 ” 和 “ for ... of ”。
Map 的属性和方法:
- size 属性,返回 Map 集合的元素个数;
- set() 方法,增加一个新元素,返回当前 Map;
- delete() 方法,删除一个元素,返回 boolean 值;
- get() 方法,返回键名对象对应的键值;
- has() 方法,检测 Map 集合中是否包含某个元素,返回 boolean 值;
- clear() 方法,清空集合,返回 undefined;
1234567891011121314151617181920 <script>let m1 = new Map(); // 创建一个空集合console.log(m1,typeof m1); // Map(0) {size: 0} 'object'let m2 = new Map([['name','名字'],['slogan','宣传标语']])console.log(m2); // Map(2) {'name' => '名字', 'slogan' => '宣传标语'}console.log(m2.size) // 2m2.set('address','地址')console.log(m2) // Map(3) {'name' => '名字', 'slogan' => '宣传标语', 'address' => '地址'}// 删除m2.delete('name');console.log(m2); // Map(2) {'slogan' => '宣传标语', 'address' => '地址'}console.log(m2.get('slogan')) // 宣传标语console.log(m2.has('address')) // trueconsole.log(m2.clear()); // undefinedconsole.log(m2) // Map(0) {size: 0}</script>
[16] Class 类:像 Java 实体类一样声明 JS 类
ES6 提供了更接近传统语言的写法,引入了 class( 类 )这个概念,作为对象的模板。
通过 class 关键字,可以定义类。
基本上,ES6 的 class 可以看作是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的 class 写法只是让对象原型的写法更加清晰、更加面向对象编程的语法而已。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<script> // ES5 构造函数写法 function Tel(brand,price){ this.brand = brand; this.price = price; } Tel.prototype.call = function(){ console.log('拨打电话') } let xiaomi = new Tel('小米',3000); console.log(xiaomi.brand,xiaomi.price); // 小米 3000 xiaomi.call(); // 拨打电话 // class 写法 class Phone { // 构造函数 constructor(brand,price){ this.brand = brand; this.price = price; } call(){ console.log('打电话'); } } let huawei = new Phone('华为',5000); console.log(huawei.brand,huawei.price); // 华为 5000 huawei.call(); // 打电话 </script> |
- static 定义静态属性和方法
12345678910111213141516 <script>class Phone{static name = '名字'static change(){console.log('方法执行了')}call(){console.log('打电话')}}let xiaomi = new Phone();console.log(xiaomi.name) // undefinedPhone.change(); // 方法执行了// xiaomi.change(); // xiaomi.change is not a functionxiaomi.call(); // 打电话</script>
- class 类继承 & 对父类方法进行重写
123456789101112131415161718192021222324 <script>class Phone{constructor(brand,price){this.brand = brand;this.price = price;}call(){console.log('打电话')}}class SmartPhone extends Phone{constructor(brand,price,color){super(brand,price);this.color = color;}// 对父类方法进行重写call(){console.log('视频通话')}}let huawei = new SmartPhone('华为',5000,'黑色');console.log(huawei); // SmartPhone {brand: '华为', price: 5000, color: '黑色'}huawei.call(); // 视频通话</script>
- class 中的 getter 和 setter 设置
1234567891011121314151617 <script>class Phone{get price(){console.log('价格被读取了')return 1000}set price(args){console.log('价格被设置了')this._price = args;// this.price = args; // 不要这样写,因为给this.price赋值的时候,会调用 set price,这样会导致无限递归直到栈溢出。}}let xiaomi = new Phone();console.log(xiaomi.price); // 价格被读取了 1000xiaomi.price = 2999; // 价格被设置了console.log(xiaomi._price); // 2999</script>
[17] 数值扩展:增加一些数值相关的方法等
- Number.EPSILON
Number.EPSILON 是 JavaScript 表示的最小精度;
EPSILON 属性的值接近于 2.2204460492503130808472633361816E-16;
12345678910111213 <script>// Number.EPSILONconsole.log(Number.EPSILON); // 2.220446049250313e-16// 数值相加console.log(0.1 + 0.2); // 0.30000000000000004console.log(0.1 + 0.2 == 0.3); // false// 实际上,我们可以这样认为:如果两个值的精度相差小于 Number.EPSILON,则这两个值相等function equal(a,b){return Math.abs(a - b) < Number.EPSILON}console.log(equal(0.1 + 0.2,0.3)); // true</script>
- 二进制和八进制:ES6 提供了二进制和八进制数值的新的写法,分别用前缀 0b 和 0o 表示。
1234567 <script>// 二进制和八进制console.log(0b1010); // 二进制 10console.log(0o777); // 八进制 511console.log(100); // 十进制 100console.log(0xff); // 十六进制 255</script>
- Number.isFinite() 用来检查一个数值是否为有限的
12345678 <script>// 判断一个数值是否为有限,如果是有限数字,返回true,否则返回false// Number.inFinite 如果检测值不是Number类型,则返回false// 也就是说,只有数值类型的值,且是有穷的,才会返回trueconsole.log(Number.isFinite(100)); // trueconsole.log(Number.isFinite(100/0)); // falseconsole.log(Number.isFinite(Infinity)); // false</script>
- Number.isNaN() 用来检查一个值是否为 NaN
12345678910 <script>// 检测一个数值是否为 NAN// Number.isNaN 如果检测值不是 Number 类型,直接返回false// 也就是说,只有数值类型的值,且是NaN,才会返回true// 具体可以看百科中,返回 NaN 的运算console.log(Number.isNaN(NaN)) // trueconsole.log(Number.isNaN(0/0)) // trueconsole.log(Number.isNaN(123)); // falseconsole.log(Number.isNaN('测试')) // false</script>
- Number.parseInt() 与 Number.parseFloat()
ES6 将全局方法 parseInt 和 parseFloat,移植到 Number 对象上面,使用不变;
12345 <script>// Number.parseInt() 与 Number.parseFloat()console.log(Number.parseInt('1234.23sdfsfd')); // 1234console.log(Number.parseFloat('1234.23sdfsfd')) // 1234.23</script>
- Math.trunc 用于去除一个数的小数部分,返回整数部分
12345 <script>// Math.trunc 用于去除一个数的小数部分,返回整数部分console.log(Math.trunc('1234.23sdfsfd')); // NaNconsole.log(Math.trunc(1234.23)); // 1234</script>
- Number.isInteger() 用来判断一个数值是否为整数
123456 <script>// Number.isInteger() 用来判断一个数值是否为整数console.log(Number.isInteger(123)); // trueconsole.log(Number.isInteger(123.12)); // falseconsole.log(Number.isInteger('123')) // false</script>
[18] 对象扩展:增加一些对象相关的方法等
ES6 新增了一些 Object 对象的方法:
- Object.is 比较两个值是否严格相等,与『===』行为基本一致(+0 与 NaN)
123456789 <script>// Object.is 比较两个值是否严格相等,与『===』行为基本一致(+0 与 NaN)console.log(Object.is(123,123)); // trueconsole.log(Object.is(123,'123')); // false// 但不同的是,console.log(Object.is(NaN,NaN)); // true// NaN与任何数值做===比较都是false,跟他自己也如此console.log(NaN === NaN); // false</script>
- Object.assign 对象的合并,将源对象的所有可枚举属性,复制到目标对象
1234567891011121314151617181920212223 <script>// Object.assign 对象的合并,将源对象的所有可枚举属性,复制到目标对象const obj1 = {http:'http://127.0.0.1',port:8080}const obj2 = {http:'http://127.0.0.1',port:8081}// 如果前后都有,后面的会覆盖前面的Object.assign(obj1,obj2);console.log(obj1); // {http: 'http://127.0.0.1', port: 8081}console.log(obj2); // {http: 'http://127.0.0.1', port: 8081}// 如果前边没有后边有,会添加Object.assign(obj1,{http:'http://localhost',port:9000,username:'root',password:'root'})console.log(obj1); // {http: 'http://localhost', port: 9000, username: 'root', password: 'root'}</script>
- proto、setPrototypeOf、 setPrototypeOf 可以直接设置对象的原型
123456789101112131415 <script>// __proto__、setPrototypeOf、 getPrototypeOf 可以直接设置对象的原型// 这种方式,并不推荐使用const school = {name:'学校名'}const city = {area:['北京','杭州']}// 设置school的原型为cityObject.setPrototypeOf(school,city);console.log(school)// 获取原型对象console.log(Object.getPrototypeOf(school)); // {area: Array(2)}</script>
[19] 模块化 ?!:简单来说就是,将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来
[20] Babel 对 ES6 模块化代码转换( 为了适配浏览器,将更新的 ES 规范转换为 ES5 规范 )
Babel 是一个 JavaScript 编译器,能够将新的ES规范语法转换成 ES5 的语法。
因为不是所有的浏览器都支持最新的 ES 规范,所以,一般项目中都需要使用 Babel 进行转换
步骤:使用 Babel 转换 JS 代码 — 打包成一个文件 — 使用时引入即可
安装工具:
- babel-cli( 命令行工具 )
- babel-preset-env( ES转换工具 )
- browserify( 打包工具, 项目中使用的是 webpack )
- 初始化项目
1 nom init -y
- 安装
1 npm i babel-cli babel-preset-env browserify -D
- 使用 babel 转换
1 npx babel js(js目录) -d dist/js(转化后的js目录) --presets=babel-preset-env
- 打包
1 npx browserify dist/js/app.js -o dist/bundle.js
- 在使用时引入 bundle.js
1 <script src="./js/bundle.js" type="module"></script>
ES7 新特性
- Array.prototype.includes 用来检测数组中是否包含某元素,返回值为布尔值,语法:arr.includes(元素值)
123456 <script>// 判断数组中是否包含某个元素let arr = [1,2,3,4,5];console.log(arr.includes(1)); // trueconsole.log(arr.includes(6)); // false</script>
- 指数运算符 ** ,即:幂运算的简化写法,例如:2的10次方:2**10
1234 <script>console.log(2 ** 10); // 1024console.log(Math.pow(2,10)); // 1024</script>
ES8 新特性
- async 函数 + await 表达式:异步函数
async 函数,其返回值为 promise 对象;而,promise 对象的结果由 async 函数执行的返回值决定
1234567891011121314151617181920 <script>async function func(){// return 123; // Promise {<fulfilled>: 123}// 若报错,则返回的Promise对象也是错误的// throw new Error('出错啦'); // Promise {<rejected>: Error: 出错啦// 如果返回的是Promise对象,那么返回的结果就是Promise对象的结果return new Promise((resolve,reject)=>{resolve('成功啦'); // Promise {<pending>} 成功})}let result = func();// console.log(result)// 调用 then 方法result.then(value => {console.log(value) // 成功啦},reason => {console.log(reason)})</script>await 函数,await 必须写在 async 函数中;await 右侧的表达式一般为 promise 对象;await 返回的是 promise 成功的值;如果 await 的 promise 失败了,就会抛出异常,需要通过 try ... catch 捕获处理。
12345678910111213141516171819202122232425 <script>// async 函数 + await 表达式:异步函数// 函数调用,返回一个promise对象function func(){return new Promise((resolve,reject) => {let data = '成功啦';resolve(data);})}// 或者,创建一个 promise 对象let p = new Promise((resolve,reject) => {resolve('成功执行')})async function fn(){let res1 = await func();console.log(res1); // 成功啦let res2 = await p;console.log(res2); // 成功执行}fn();</script>
- 对象方法扩展
1234567891011121314 <script>// Object.values()方法:返回一个给定对象的所有可枚举属性值的数组;// Object.entries()方法:返回一个给定对象自身可遍历属性 [key,value] 的数组;// Object.getOwnPropertyDescriptors() 该方法:返回指定对象所有自身属性的描述对象;let obj = {name:'名称',age:18}console.log(Object.keys(obj)); // ['name', 'age'] // 键console.log(Object.values(obj)); // ['名称', 18] // 值console.log(Object.entries(obj)); // [['name', '名称'],['age', 18]]console.log(Object.getOwnPropertyDescriptors(obj)); // 说明:一个详细的描述对象</script>
ES9 新特性
- 在对象中使Rest参数与spread扩展运算符
1234567891011121314 <script>// 在对象中使用扩展运算符function connect({host,port,...user}){console.log(host); // http://127.0.0.1console.log(port); // 8080console.log(user); // {username: 'root', password: 'root'}}connect({host:'http://127.0.0.1',port:8080,username:'root',password:'root'})</script>
123456789101112131415161718 <script>// 对象中的rest参数const skill1 = {q:'技能1'}const skill2 = {w:'技能2'}const skill3 = {e:'技能3'}const skill4 = {r:'技能4'}// 对象合并const skill = {...skill1,...skill2,...skill3,...skill4}console.log(skill); // {q: '技能1', w: '技能2', e: '技能3', r: '技能4'}</script>
正则扩展:简化和增强正则匹配
ES10 新特性
Object.fromEntries 将二维数组或者map转换成对象trimStart 和 trimEnd 去除字符串前后的空白字符Array.prototype.flat 与 flatMap 将多维数组降维Symbol.prototype.description 获取Symbol的字符串描述
ES11 新特性
String.prototype.matchAll 用来得到正则批量匹配的结果类的私有属性:私有属性外部不可访问直接Promise.allSettled 获取多个promise执行的结果集可选链操作符:简化对象存在的判断逻辑动态 import 导入:动态导入模块,什么时候使用什么时候导入BigInt:大整型- globalThis 对象:始终指向全局对象 window
12345 <script>// Window {window: Window, self: Window, document: document, name: '', location: Location, …}console.log(globalThis);console.log(window);</script>