文章目录

  • 一 ECMAScript 相关介绍
    • 1 什么是 ECMA
    • 2 什么是 ECMAScript
    • 3 什么是 ECMA-262
    • 4 谁在维护 ECMA-262
    • 5 为什么要学习 ES6
    • 6 ES6 兼容性
  • 二 ECMASript 6 新特性
    • 1. let 关键字
      • 案例
    • 2. const 关键字
    • **3. 变量的解构赋值**
      • 应用场景:
    • 4. 模板字符串
      • 应用场景:
    • 5. 简化对象写法
      • 应用场景:
    • 6. 箭头函数
      • 案例1:箭头函数 this 始终指向声明时所在作用域下 this 的值,call 等方法无法改变其指向
      • 案例2:筛选偶数
      • 案例3:点击 div两秒后变成粉色
    • 7. 函数参数默认值设定
    • 8. rest 参数
      • 应用场景:
      • 案例1:求不定个数数字的和
    • 9. spread 扩展运算符
    • 10. Symbol
      • 10.1 Symbol 基本介绍与使用
        • Symbol 的特点
        • Symbol 的创建
      • 10.2 对象添加 Symbol 类型的属性
      • 10.3 Symbol 内置值
    • 11. 迭代器
      • 11.1 定义
      • 11.2 工作原理
      • 11.3 自定义遍历数据
    • 12. Generator 生成器函数
      • 12.1 生成器函数的声明和调用
      • **12.2 生成器函数的参数传递**
      • 2.3 生成器函数案例
    • 13. Promise
      • 13.1 Promise 的定义和使用
      • **13.2 Promise 封装读取文件**
      • **13.3 Promise 封装 Ajax 请求**
      • **13.4 Promise.prototype.then 方法**
      • 13.4 链式调用
      • 13.5 Promise.prototype.catch
      • **13.6 链式调用练习-多个文件读取**
    • 14. Set
    • 15. Map
    • 16. class 类
      • 16.1 复习 ES5 function 构造函数 的继承
      • **16.2 extends 类继承和方法的重写**
      • 16.3 静态成员
      • 16.4 getter 和 setter
    • 17. 数值扩展
    • 18. 对象方法扩展
      • 18.1 Object.is()
      • 18.2 Object.assign
      • 18.3 Object.setPrototypeOf 和 Object.getPrototypeof
    • 19. ES6 模块化
      • 19.1 模块化的好处
      • 19.2 模块化规范产品
      • 19.3 ES6 模块化语法
        • **1 模块导出数据语法**
          • 1 分别暴露
          • 2 统一暴露
          • 3 默认暴露
        • 2 模块导入数据语法
          • 1 通用导入方式
          • 2 解构赋值导入
          • 3. 简便方式导入,只能用于默认暴露
        • **3 ES6 使用模块化方式二**
      • **19.4 使用 babel 对模块化代码转换**
        • 1. 安装工具
        • 2. 编译
        • 3 打包
      • **19.5 ES6 模块化引入 npm 安装的包**
  • 三 ECMASript 7 新特性
    • 1. Array.prototype.includes
    • 2. 指数运算符
  • **四 ECMAScript 8 新特性**
    • 1. async 和 await
      • 1.1 async
      • **1.2 await**
      • **1.3 综合应用-读取文件**
      • **1.4 综合应用-封装ajax**
    • **2. Object.values 和 Object.entries**

一 ECMAScript 相关介绍

1 什么是 ECMA

ECMA(European Computer Manufacturers Association)中文名称为欧洲计算机制造商协会,这个组织的目标是评估、开发和认可电信和计算机标准,1994 年后该组织改名为Ecma 国际

2 什么是 ECMAScript

ECMAScript 是由 Ecma 国际通过ECMA-262 标准化的脚本程序设计语言。

ECMASCRIPT

3 什么是 ECMA-262

Ecma 国际制定了许多标准,而ECMA-262 只是其中的一个,所有标准列表查看:http://www.ecma-international.org/publications/standards/Standard.htm

ECMA-262 历史版本查看网址: http://www.ecma-international.org/publications/standards/Ecma-262-arch.htm

  • ES5 是 ECMAScript 第5版,2009年发布

  • ES6 是 ECMAScript 第6版,2015年发布,也叫 ES2015

  • 从 ES6 开始,每年发布一个版本,版本号比年份最后一位大 1

4 谁在维护 ECMA-262

TC39(Technical Committee 39)是推进ECMAScript 发展的委员会。其会员都是公司(其中主要是浏览器厂商,有苹果、谷歌、微软、因特尔等)。TC39 定期召开会议,会议由会员公司的代表与特邀专家出席。

5 为什么要学习 ES6

  • ES6 的版本变动内容最多,具有里程碑意义

  • ES6 加入许多新的语法特性,编程实现更简单、高效

  • ES6 是前端发展趋势,就业必备技能

6 ES6 兼容性

可查看兼容性:http://kangax.github.io/compat-table/es6/

二 ECMASript 6 新特性

1. let 关键字

let 关键字用来声明变量,使用 let 声明的变量有几个特点

  • 不允许重复声明

  • 块级作用域

  • 不存在变量提升

  • 不影响作用域链

应用场景:以后声明变量使用let 就对了

案例
  • 给多个 div 循环注册点击事件

    • 错误示例
<h2 class="page-header">点击切换颜色</h2>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div><script>// 错误示例,divs.length === 3document.addEventListener('DOMContentLoaded', function () {let divs = document.querySelectorAll('div');for (var i = 0; i < divs.length; i++) {divs[i].addEventListener('click', function () {divs[i].style.backgroundColor = 'pink';});}});/*i 为当前作用域下的共享变量。当每次点击 div 的时候,各个点击事件共享 i 的值,此时 i = 3,将报错
*/
</script>

正确实例:将以上代码中的 var 改为 let。

  • 1s 后循环输出所有数字

    • 错误示例
for (var i = 1; i <= 5; i++) {setTimeout(() => {console.log(i);}, 1000);
}
/*输出:6 6 6 6 6循环从1-5的时间很短暂,远不及 1s。此时五个异步事件瞬间加入到异步事件队列中,等待 1s后依次执行。而此时i为6,故瞬间输出 5 个 6。异步事件队头(1) console.log(i);(2) console.log(i);(3) console.log(i);(4) console.log(i);(5) console.log(i);
*/
  • 正确示例
for (let j = 1; j <= 5; j++) {setTimeout(() => {console.log(j);}, 1000);
}
// 输出:1 2 3 4 5
// let 有块级作用域,每个 j 都会形成一个自己的块级作用域,与相应的异步事件共享:
// {j = 1;} {j = 2;} {j = 3;} {j = 4;} {j = 5;}
  • 解决方法2
// 给每一个 i 设置一个立即执行函数,会形成自己的块级作用域,不影响外部变量。
for (var i = 1; i <= 5; i++) {(function (i) {setTimeout(() => {console.log(i);}, 1000);})(i);
}

2. const 关键字

const 关键字用来声明常量,const 声明有以下特点

  • 声明必须赋初始值

  • 标识符一般为大写

  • 不允许重复声明

  • 值不允许修改

  • 块级作用域

    注意:对象属性修改和数组元素变化不会出发 const 错误

应用场景:声明对象类型使用 const,非对象类型声明选择 let

const arr = [1, 2, 3, 4];
arr.push(5, 6);
console.log(arr);   // 不报错const obj = {uname: 'rick',age: 30
}
obj.age = 40;  // 只要不改变地址,就不报错

3. 变量的解构赋值

ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为 解构赋值
数组的解构赋值

const arr = ['red', 'green', 'blue'];
let [r, g, b] = arr;

对象的解构赋值

const obj = {uname: 'rick',age: 30,sayHi: function () {console.log('hello');},sayBye() {console.log('Bye~');}
}
let {name, age, sayHi} = obj;
let {sayBye} = obj;
应用场景:

频繁使用对象方法、数组元素,就可以使用解构赋值形式

4. 模板字符串

模板字符串(template string)是增强版的字符串,用反引号 `` `标识,特点

  • 字符串中可以出现换行符

  • 可以使用 ${xxx} 形式输出变量,近似 EL 表达式

应用场景:

当遇到字符串与变量拼接的情况使用模板字符串

let name = 'jack';
console.log(`hello, ${name}`);let ul = `<ul><li>apple</li><li>banana</li><li>peach</li></ul>`

5. 简化对象写法

ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁

应用场景:

对象简写形式简化了代码,所以以后用简写就对了

let uname = 'rick';
let age = 30;
let sayHi = function () {console.log('Hi');
}// 创建对象,因属性、方法 的 k v 同名,可以简化
const obj = {uname,age,sayHi() { console.log('Hi'); }
}

6. 箭头函数

ES6 允许使用箭头=>定义函数

  • function 写法

    function fn(param1, param2, …, paramN) { // 函数体return expression;
    }
    
  • => 写法

let fn = (param1, param2, …, paramN) => {// 函数体return expression;
}

注意

  • 如果形参只有一个,小括号可以省略
  • 如果函数体只有一条语句,花括号可以省略,函数的返回值为该条语句的执行结果,如果是 return 语句,return 必须省略
  • 箭头函数 this 是静态的,始终指向声明时所在作用域下 this 的值

this就是调用方法的那个对象

箭头函数 this 始终指向声明时所在作用域下 this 的值(不停的往上找),call 等方法无法改变其指向

  • 箭头函数不能作为构造函数实例化
  • 不能使用 arguments
// 省略小括号
let fn1 = n => {return n * n;
}// 省略花括号
let fn2 = (a + b) => a + b;// 箭头函数 this 始终指向声明时所在作用域下 this 的值
const obj = {a: 10,getA () {let fn3 = () => {console.log(this);       // obj {...}console.log(this.a);    // 10}fn3();}
}
案例1:箭头函数 this 始终指向声明时所在作用域下 this 的值,call 等方法无法改变其指向
let obj = {uname: 'rick',age: 30
};
let foo = () => { console.log(this) }
let bar = function () { console.log(this) }// call 对箭头函数无效
foo.call(obj); // window
bar.call(obj); // obj {...}
案例2:筛选偶数
const arr = [1, 6, 9, 10, 100, 25]
// const result = arr.filter(function(item) {
//     if(item % 2 === 0) {
//         return true;
//     } else {
//         return false;
//     }
// });const result = arr.filter(item => item % 2 === 0);console.log(result);
案例3:点击 div两秒后变成粉色
  • 方案1:使用 _this 保存 div 下的 this,从而设置 div 的 style 属性
<style>div {width: 200px;height: 200px;background: #58a;}
</style><div id="ad"></div><script>let ad = document.getElementById('ad')ad.addEventListener("click", function(){//保存 this 的值// let _this = this;setTimeout(() => {// console.log(this);// _this.style.background = 'pink';this.style.background = 'pink';}, 2000);})
</script>
  • 方案2:使用 => 箭头函数

    // 箭头函数适合与 this 无关的回调. 定时器, 数组的方法回调
    // 箭头函数不适合与 this 有关的回调.  事件回调, 对象的方法
    div.addEventListener('click', function () {setTimeout(() => {console.log(thid); // <div id="ad" style="background: pink;"></div>this.style.backgroundColor = 'pink';}, 2000);
    });
    

7. 函数参数默认值设定

ES6 允许给函数参数设置默认值,当调用函数时不给实参,则使用参数默认值
具有默认值的形参,一般要靠后。

let add = (x, y, z=3) => x + y + z;
console.log(add(1, 2)); // 6

可与解构赋值结合

function connect({ host = '127.0.0.1', uesername, password, port }) {console.log(host); // 127.0.0.1console.log(uesername);console.log(password);console.log(port);
}
connect({// host: 'docs.mphy.top',uesername: 'root',password: 'root',port: 3306
})

8. rest 参数

ES6 引入 rest 参数,用于获取函数的实参,用来代替 arguments,作用与 arguments 类似,将接收的参数序列转换为一个数组对象(arguments 是伪数组)
语法格式:fn(a, b, ...args),写在参数列表最后面

应用场景:

rest 参数非常适合不定个数参数函数的场景

let fn = (a, b, ...args) => {console.log(a);console.log(b);console.log(args);
};
fn(1,2,3,4,5);// 1 2 Array(4)
案例1:求不定个数数字的和
let add = (...args) => {let sum = args.reduce((pre, cur) => pre + cur, 0);return sum;
}
console.log(add(1, 2, 3, 4, 5)); // 15

9. spread 扩展运算符

扩展运算符spread也是三个点...,它好比 rest 参数的逆运算,将一个数组、伪数组转为用逗号分隔的参数序列,对数组进行解包,扩展运算符也可以将对象解包
可用在调用函数时,传递的实参,将一个数组转换为参数序列(与rest参数的区别,一个用在形参,一个实参)

  • 展开数组
function fn(a, b, c) {console.log(arguments);console.log(a + b + c);
}
let arr = ['red', 'green', 'blue'];
fn(...arr)
// [Arguments] { '0': 'red', '1': 'green', '2': 'blue' }
// redgreenblue
  • 案例1:数组合并
let A = [1, 2, 3];
let B = [4, 5, 6];
let C = [...A, ...B];
console.log(C); // [1, 2, 3, 4, 5, 6]
  • 案例2:数组克隆,这种数组克隆属于浅拷贝
let arr1 = ['a', 'b', 'c'];
let arr2 = [...arr1];
console.log(arr2); // ['a', 'b', 'c']
  • 案例3:将伪数组转换为真实数组
const divs = document.querySelectorAll('div');
let divArr = [...divs];
console.log(divArr);
  • 案例4:对象合并
let obj1 = {a: 123
};
let obj2 = {b: 456
};
let obj3 = {c: 789
};
let obj = { ...obj1, ...obj2, ...obj3 };
console.log(obj);
// { a: 123, b: 456, c: 789 }

10. Symbol

10.1 Symbol 基本介绍与使用

JavaScript 的七种基本数据类型

  • 值类型(基本类型):string、number、boolean、undefined、null、symbol

  • 引用数据类型:object(包括 array、function)

ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值。它是 JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型

Symbol 的特点

  • Symbol 的值是唯一的,用来解决命名冲突的问题

  • Symbol 值不能与其他数据进行运算

  • Symbol 定义的对象属性不能使用 for…in 循环遍历,但是可以使用 Reflect.ownKeys 来获取对象的所有键名

Symbol 的创建

  • 创建 Symbol()创建

  • 使用 Symbol.for() 方法创建,名字相同的 Symbol 具有相同的实体

  • 输出 Symbol 变量的描述,使用 description 属性

// Symbol() 创建
let s = Symbol();
console.log(s, typeof s);let s2 = Symbol('cess');
let s3 = Symbol('cess');
console.log(s2 === s3);  // false// Symbol.for 创建
let s4 = Symbol.for('cess');
let s5 = Symbol.for('cess');
console.log(s2 === s3);  // true// 不能与其他数据进行运算
let result = s + 100;
let result = s > 100;
let result = s + s;let f = Symbol('测试');
console.log(f.description); // 测试

10.2 对象添加 Symbol 类型的属性

案例:安全的向对象中添加属性和方法。
分析:如果直接向对象中添加属性或方法,则原来对象中可能已经存在了同名属性或方法,会覆盖掉原来的。所以使用 Symbol 生成唯一的属性或方法名,可以更加安全的添加

// 这是一个 game 对象,假设我们不知道里面有什么属性和方法
const game = {uname: '俄罗斯方块',up: function () { },down: function () { }
}// 通过 Symbol 生成唯一的属性名,然后给 game 添加方法
let [up, down] = [Symbol('up'), Symbol('down')];
game[up] = function () {console.log('up');
}
game[down] = function () {console.log('down');
}// 调用刚刚创建的方法
game[up]();
game[down]();let youxi = {name:"狼人杀",[Symbol('say')]: function(){console.log("我可以发言")},[Symbol('zibao')]: function(){console.log('我可以自爆');}
}console.log(youxi)

10.3 Symbol 内置值

除了定义自己使用的 Symbol 值以外,ES6 还提供了11 个内置的 Symbol 值,指向语言内部使用的方法。可以称这些方法为魔术方法,因为它们会在特定的场景下自动执行

方法 描述
Symbol.hasInstance 当其他对象使用 instanceof运算符,判断是否为该对象的实例时,会调用这个方法
Symbol.isConcatSpreadable 对象的 Symbol.isConcatSpreadable属性等于的是一个布尔值,表示该对象用于Array.prototype.concat()时,是否可以展开
Symbol.species 创建衍生对象时,会使用该属性
Symbol.match 当执行 str.match(myObject)时,如果该属性存在,会调用它,返回该方法的返回值。
Symbol.replace 当该对象被 str.replace(myObject)方法调用时,会返回该方法的返回值
Symbol.search 当该对象被 str.search(myObject)方法调用时,会返回该方法的返回值
Symbol.split 当该对象被 str.split(myObject)方法调用时,会返回该方法的返回值
Symbol.iterator 对象进行 for…of 循环时,会调用 Symbol.iterator方法,返回该对象的默认遍历器
Symbol.toPrimitive 该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值。
Symbol. toStringTag 在该对象上面调用 toString()方法时,返回该方法的返回值
Symbol. unscopables 该对象指定了使用 with关键字时,哪些属性会被 with环境排除

案例1:Symbol.hasInstance 方法判断是否属于这个对象时被调用

class A {static [Symbol.hasInstance]() {console.log('判断是否属于这个对象时被调用');}
}
let obj = {};
console.log(obj instanceof A)
// 判断是否属于这个对象时被调用
// false

案例2:数组使用 concat 方法时,是否可以展开

let arr1 = [1, 2, 3];
let arr2 = [4, 5, 6];
let arr3 = [4, 5, 6];
arr2[Symbol.isConcatSpreadable] = false;
console.log(arr1.concat(arr2));
// [ 1, 2, 3, [ 4, 5, 6, [Symbol(Symbol.isConcatSpreadable)]: false ] ]
console.log(arr1.concat(arr3));
// [ 1, 2, 3, 4, 5, 6 ]

11. 迭代器

11.1 定义

迭代器Iterator是一种接口,为各种不同的数据结构提 供统一的访问机制。任何数据结构只要部署 Iterator 接口(在 js 中接口就是对象的一个属性),就可以完成遍历操作

  • ES6 创造了一种新的遍历命令for...of循环,Iterator 接口主要供 for...of 消费

  • for...in 取的是索引,for...of 取的是 value

  • 原生具备 iterator 接口的数据(可用 for of 遍历)

    • Array

    • Arguments

    • Set

    • Map

    • String

    • TypedArray

    • NodeList

案例:使用 next() 方法遍历原生自带 iterator 接口的数据

// 遍历数组
const xiyou = ['唐僧', '孙悟空', '猪八戒', '沙僧'];//使用 for...of 遍历数组
for (let v of xiyou) {console.log(v);
}let iterator = xiyou[Symbol.iterator]();//调用对象的next方法
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());// 遍历 Map
const map = new Map();
map.set('a', 1);
map.set('b', 2);
map.set('c', 3);
let iter = map[Symbol.iterator]();
// next() 方法每执行一次,指针自增
console.log(iter.next());   // { value: [ 'a', 1 ], done: false }
console.log(iter.next()); // { value: [ 'b', 2 ], done: false }
console.log(iter.next()); // { value: [ 'c', 3 ], done: false }
console.log(iter.next()); // { value: undefined, done: true }

上面的案例只是为了证明这些数据类型自带 iterator 接口,实际上直接使用 for...of 方法即可完成,使用 for [k, v] of map 来遍历 Map 数据结构中的键和值

const map = new Map();
map.set('a', 1);
map.set('b', 2);
map.set('c', 3);for (let [k, v] of map) {console.log(k, v);
}// 结果
a 1
b 2
c 3

11.2 工作原理

1 创建一个指针对象,指向当前数据结构的起始位置

2 第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员

3 接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员

4 每调用 next 方法返回一个包含 value 和 done 属性的对象

应用场景:需要自定义遍历数据的时候,要想到迭代器

11.3 自定义遍历数据

我们可以通过给数据结构添加自定义 [Symbol.iterator]() 方法来使该数据结构能够直接被遍历,从而使 for...of 能够直接遍历指定数据

const banji = {name: "终极一班",stus: ['xiaoming', 'xiaoning', 'xiaotian', 'knight'],[Symbol.iterator]() {let index = 0; // 索引变量let _this = this;return {next: function () {if (index < _this.stus.length) {const result = { value: _this.stus[index], done: false };index++; // 下标自增return result;   // 返回结果} else {return {value: undefined, done: true};}}};}
}// 遍历这个对象
for (let v of banji) {console.log(v);
}

12. Generator 生成器函数

12.1 生成器函数的声明和调用

生成器函数是 ES6 提供的一种 异步编程解决方案,语法行为与传统采用纯回调函数完全不同

一般函数从开始运行到它结束之前,不会被任何事情打断。而生成器可以在执行当中暂停自身,可以立即恢复执行,也可以过一段时间之后恢复执行,所以生成器它不能像普通函数那样保证运行到完毕

生成器在每次 暂停/恢复 都提供了一个双向传递信息的功能,生成器可以返回一个值,恢复它的控制代码也可以接收一个值。

  • 使用 function * generator()yield 可以声明一个生成器函数,* 的位置随意
function * generator(){};
function *generator(){};
function* generator(){};
function*generator(){};
  • 生成器函数返回的结果是迭代器对象,调用迭代器对象的 next() 方法可以得到 yield 语句后的值
  • 每一个 yield 相当于函数的暂停标记,类似 return 要返回值,但不退出函数,每调用一次 next(),生成器函数就往下执行一段
  • next 方法可以传递实参,作为 yield 语句的返回值
    如下生成器函数中,3 个 yield 语句将函数内部分成了 4 段
// 生成器其实就是一个特殊的函数
// 步编程  纯回调函数  node fs  ajax mongodb
// yield 暂停标记
function * gen(){// console.log(111);yield '一只没有耳朵';// console.log(222);yield '一只没有尾部';// console.log(333);yield '真奇怪';// console.log(444);
}let iterator = gen();
console.log(iterator.next());   // 每调一次,执行一段,并返回yield后面的值
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());// 遍历
for(let v of gen()) console.log(v);
}

12.2 生成器函数的参数传递

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 iter = generator('AAA'); // 传给生成器第 1 段
console.log(iter.next());
console.log(iter.next('BBB'));
console.log(iter.next('CCC'));
console.log(iter.next('DDD'));// 结果
AAA
Object{value: 111, done: false}
BBB
Object{value: 222, done: false}
CCC
Object{value: 333, done: false}
DDD
Object{value: undefined, done: true}

2.3 生成器函数案例

案例1: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);iter.next();}, 1000);
}function two() {setTimeout(() => {console.log(222);iter.next();}, 2000);
}function three() {setTimeout(() => {console.log(333);}, 3000);
}function * generator() {yield one();yield two();yield three();
}let iter = generator();
iter.next();
  • 案例2:生成器函数模拟每隔1s获取商品数据
function getUsers() {setTimeout(() => {let data = '用户数据';iter.next(data); // 传参给生成器函数的第 2 段,后面类似}, 1000);
}function getOrders() {setTimeout(() => {let data = '订单数据';iter.next(data);}, 1000);
}function getGoods() {setTimeout(() => {let data = '商品数据';iter.next(data);}, 1000);
}function * generator() {let users = yield getUsers();console.log(users);let orders = yield getOrders();console.log(orders);let goods = yield getGoods();console.log(goods);
}let iter = generator();
iter.next();

13. Promise

13.1 Promise 的定义和使用

Promise是 ES6 引入的异步编程的新解决方案,语法上 Promise 是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果

一个 Promise 必然处于以下几种状态之一

  • 待定 pending:初始状态,既没有被兑现,也没有被拒绝

  • 已兑现 fulfilled:意味着操作成功完成

  • 已拒绝 rejected:意味着操作失败

Promise 的使用

  • Promise 构造函数new Promise((resolve, reject) => {})
  • Promise.prototype.then()方法
  • Promise.prototype.catch()方法
let p = new Promise(function (resolve, reject) {// 使用 setTimeout 模拟请求数据库数据操作setTimeout(function () {let isRight = true;    // 这个异步请求数据库数据操作是否正确返回数据if (isRight) {let data = '数据库中的数据';resolve(data);    // 设置 Promise 对象的状态为操作成功} else {let err = '数据读取失败!'reject(err);   // 设置 Promise 对象的状态为操作失败}}, 1000);
});
p.then(function (value) {console.log(value);
}, function (reason) {console.error(reason);
})

13.2 Promise 封装读取文件

// 使用 nodejs 的 fs 读取文件模块
const fs = require('fs');const p = new Promise(function (resolve, reject) {fs.readFile('./resources/为学.txt', (err, data) => {if (err) reject(err);    // err 是一个异常对象resolve(data);})
})p.then(function (value) {console.log(value.toString());   // 转为字符串输出
}, function (reason) {console.log('读取失败!!');
})

13.3 Promise 封装 Ajax 请求

const p = new Promise((resolve, reject) => {const xhr = new XMLHttpRequest();xhr.open('get', 'https://api.apiopen.top/getJoke');xhr.send();xhr.onreadystatechange = function () {if (xhr.readyState === 4) {if (xhr.status >= 200 && xhr.status < 300) {resolve(xhr.response);  // 成功} else {reject(xhr.status);    // 失败}}}
});// 指定回调
p.then(function (value) {console.log(value);
}, function (reason) {console.error(reason);
})

13.4 Promise.prototype.then 方法

Promise.prototype.then 方法返回的结果依然是 Promise 对象,对象状态由回调函数的执行结果决定
具体情况如下

  • 若 then 方法没写写返回值,则 then 方法返回的对象的状态值为成功 fulfilled,返回结果值为 undefined
const p = new Promise((resolve, reject) => {setTimeout(() => {resolve('用户数据')// reject('出错了');}, 1000);
})
// 未设定返回值
const res = p.then((value) => {console.log(value);
}, (reason) => {console.warn(reason);
})
// 打印 then 方法的返回值
console.log(res);

  • 如果回调函数中返回的结果是非 Promise 类型的属性,则 then 方法返回的对象,其状态为成功 fulfilled,返回结果值取决于 then 方法所执行的是哪个函数(resolve 或 reject)
const p = new Promise((resolve, reject) => {setTimeout(() => {// resolve('用户数据')reject('出错了');}, 1000);
})// 返回的非 Promise 对象
const res = p.then((value) => {console.log(value);return '成功了!!';
}, (reason) => {console.warn(reason);return '出错啦!!'
})
// 打印 then 方法的返回值
console.log(res);

RES

PROMISE:{:'出错啦!!!

[[PROTOTYPE]]: PROMISE

[[PROMISESTATE]]: “FULFILLED”

[[PROMISERESULT]]:"出错啦!

如果回调函数中返回的结果是 Promise 类型 return new Promise(),则 then 方法返回的 Promise 对象状态与该返回结果的状态相同,返回值也相同

const p = new Promise((resolve, reject) => {setTimeout(() => {resolve('用户数据')// reject('出错了');}, 1000);
})
const res = p.then((value) => {console.log(value);// 返回 Promise 对象return new Promise((resolve, reject) => {resolve('(1)成功了!!!');// reject('(1)出错了!!!')})
}, (reason) => {console.warn(reason);return new Promise((resolve, reject) => {// resolve('(2)成功了!!!');reject('(2)出错了!!!')})
})
// 打印 then 方法的返回值
console.log(res);

  • 如果回调函数中返回的结果是 throw 语句抛出异常,则 then 方法的对象的状态值为 rejected,返回结果值为 throw 抛出的字面量或者 Error 对象
const p = new Promise((resolve, reject) => {setTimeout(() => {resolve('用户数据');}, 1000);
});
const res = p.then((value) => {console.log(value);return new Promise((resolve, reject) => {throw new Error('错误了!!');})
});
// 打印结果
console.log(res);

13.4 链式调用

Promise.prototype.then 方法返回的结果还是 Promise 对象,这意味着我们可以继续在该结果上使用 then 方法,也就是链式调用,杜绝回调地狱

const p = new Promise(resolve=>{}, reject=>{});
p.then(value=>{}, reason=>{})
.then(value=>{}, reason=>{})
.then(value=>{}, reason=>{})
...

13.5 Promise.prototype.catch

catch() 方法返回一个 Promise,并且处理拒绝的情况
它的行为与调用 Promise.prototype.then(undefined, onRejected) 相同

obj.catch(onRejected);
等同于
obj.then(undefined, onRejected);

语法

p.catch(onRejected);p.catch(function(reason) {// 拒绝
});

举例

var p1 = new Promise(function (resolve, reject) {resolve('Success');
});p1.then(function (value) {console.log(value); // "Success!"throw 'oh, no!';
}).catch(function (e) {console.log(e); // "oh, no!"
}).then(function () {console.log('有 catch 捕获异常,所以这句输出');
}, function () {console.log('没有 catch 捕获异常,这句将不会输出');
});// 结果
Success
oh, no!
有 catch 捕获异常,所以这句输出

13.6 链式调用练习-多个文件读取

const fs = require('fs');// 回调方式
fs.readFile('./resources/为学.md', (err, data1)=>{fs.readFile('./resources/插秧诗.md', (err, data2)=>{fs.readFile('./resources/观书有感.md', (err, data3)=>{let result = data1 + '\r\n' +data2  +'\r\n'+ data3;console.log(result);});});
});// promise 方式
new Promise((resolve, reject) => {fs.readFile('./resources/users.md', (err, data) => {resolve(data);  // 设置状态})
}).then(value => {return new Promise((resolve, reject) => {// value 为第一次读取的文件数据,data 为第二次(当前)读取的数据fs.readFile('./resources/orders.md', (err, data) => {resolve([value, data]);   // 将上轮读取结果和本轮合并传到下一轮轮读取操作});});
}).then(value => {return new Promise((resolve, reject) => {fs.readFile('./resources/goods.md', (err, data) => {// value 为上一轮传递过来的文件数据数组value.push(data);// 传给下一轮操作resolve(value);});});
}).then(value => {// 合并数组元素,输出console.log(value.join('\r\n'));
});

14. Set

ES6 提供了新的数据结构Set(集合),它类似于数组,但 成员的值都是唯一的,集合实现了 iterator 接口,所以可以使用扩展运算符 … 和 for…of 进行遍历

属性和方法

  • st.size:返回集合个数
  • st.add(item):往集合中添加一个新元素 item,返回当前集合
  • st.delete(item):删除集合中的元素,返回 boolean 值
  • st.has(item):检测集合中是否包含某个元素,返回 boolean 值
  • st.clear():清空集合
  • 集合转为数组:[…st]
  • 合并两个集合:[…st1, …st2]

案例1: 数组去重

let arr1 = [1, 2, 2, 3, 3, 3, 4, 1, 2];
let res1 = [...new Set(arr1)];
console.log(res1); // [ 1, 2, 3, 4 ]

案例2:数组求交集

let arr2_1 = [1, 2, 2, 3, 4, 5];
let arr2_2 = [3, 6, 6, 7, 1, 4];
let res2 = arr2_1.filter(v => new Set(arr2_2).has(v))
console.log(res2); // [ 1, 3, 4 ]

案例3:数组求并集

let arr3_1 = [1, 2, 2, 3, 4, 5];
let arr3_2 = [3, 6, 6, 7, 1, 4];
let res3 = [...new Set([...arr3_1, ...arr3_2])];
console.log(res3); // [ 1, 2, 3, 4, 5, 6, 7 ]

案例4:数组求差集

let arr4_1 = [1, 2, 2, 3, 4, 5];
let arr4_2 = [3, 6, 6, 7, 1, 4];
let res4 = [...new Set(arr4_1)].filter(v => !(new Set(arr4_2).has(v)))
console.log(res4); // [ 2, 5 ]

15. Map

ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合。但是 “键” 的范围不限于字符串,各种类型的值(包括对象)都可以当作键。Map 也实现了 iterator 接口,所以可以使用扩展运算符 … 和 for…of 进行遍历

let mp1 = new Map();
mp1.set('aaa', 111);
mp1.set('bbb', 222);
mp1.set('ccc', 333);let mp2 = new Map([['aaa', 111],['bbb', 222],['ccc', 333]
]);console.log(mp1['aaa']); // 111
console.log(mp2.get('bbb')); // 222

Map 的属性和方法:(k 为键,v为值)

  • size:返回 Map 的元素(键值对)个数
  • set(k, v):增加一个键值对,返回当前 Map
  • get(k):返回键值对的键值
  • has():检测 Map 中是否包含某个元素
  • clear():清空集合,返回 undefined
let m = new Map();//添加元素
m.set('name','school');
m.set('change', function(){console.log("我们可以改变你!!");
});
let key = {school : 'ATSCHOOL'
};
m.set(key, ['北京','上海','深圳']);//size
console.log(m.size);//删除
m.delete('name');//获取
console.log(m.get('change'));
console.log(m.get(key));//清空
m.clear();//遍历
for(let v of m) {console.log(v);
}

16. class 类

可跳转 JS 高阶 class
ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class 关键字,可以定义类。基本上,ES6 的 class 可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的 class 写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已

16.1 复习 ES5 function 构造函数 的继承

// 手机
function Phone(brand, price){
this.brand = brand;
this.price = price;
}Phone.prototype.call = function(){
console.log("我可以打电话");
}// 智能手机
function SmartPhone(brand, price, color, size){
Phone.call(this, brand, price);
this.color = color;
this.size = size;
}// 设置子级构造函数的原型
SmartPhone.prototype = new Phone;
SmartPhone.prototype.constructor = SmartPhone;// 声明子类的方法
SmartPhone.prototype.photo = function(){
console.log("我可以拍照")
}SmartPhone.prototype.playGame = function(){
console.log("我可以玩游戏");
}const chuizi = new SmartPhone('锤子',2499,'黑色','5.5inch');console.log(chuizi);

16.2 extends 类继承和方法的重写

ES6 中直接使用 extends 语法糖(更简洁高级的实现方式)来实现继承,同时可以重写父类的方法,直接在子类中重新写一次要重写的方法即可覆盖父类方法。

class Phone{// 构造方法constructor(brand, price){this.brand = brand;this.price = price;}// 父类的成员属性call(){console.log("我可以打电话!!");}
}class SmartPhone extends Phone {// 构造方法constructor(brand, price, color, size){super(brand, price); // Phone.call(this, brand, price)this.color = color;this.size = size;}photo() {console.log("拍照");}playGame() {console.log("玩游戏");}// 子类重写父类方法,super.call()可以调父类方法call() {console.log('我可以进行视频通话');}
}const xiaomi = new SmartPhone('小米',799,'黑色','4.7inch');
// console.log(xiaomi);
xiaomi.call();
xiaomi.photo();
xiaomi.playGame();

16.3 静态成员

函数对象的属性 方法是属于函数对象的,其创建的实例对象无法使用,这就是静态成员

function Phone(){}
Phone.name = '手机';
Phone.change = function(){console.log("我可以改变世界");
}
Phone.prototype.size = '5.5inch';let nokia = new Phone();
// console.log(nokia.name);
// nokia.change();
console.log(nokia.size);
class Phone{//静态属性static name = '手机';static change(){console.log("我可以改变世界");}
}let nokia = new Phone();
console.log(nokia.name); // undefined
console.log(Phone.name);

16.4 getter 和 setter

实际上,getter和setter是 ES5(ES2009)提出的特性 当属性拥有 get/set 特性时,属性就是访问器属性。代表着在访问属性或者写入属性值时,对返回值做附加的操作。而这个操作就是 getter/setter 函数

使用场景: getter 是一种语法,这种 get 将对象属性绑定到 查询该属性时将被调用的函数。适用于某个需要动态计算的成员属性值的获取。setter 则是在修改某一属性时所给出的相关提示

// get 和 set
class Phone {get price() {console.log("价格属性被读取了");return 'iloveyou';}set price(newVal) {console.log('价格属性被修改了');}
}//实例化对象
let s = new Phone();// console.log(s.price);
s.price = 'free';

17. 数值扩展

  1. Number.EPSILON 是 JavaScript 表示的最小精度,一般用来处理浮点数运算。例如可以用于两个浮点数的比较
let equal = (x, y) => Math.abs(x - y) < Number.EPSILON;console.log(0.1 + 0.2 === 0.3); // false
console.log(equal(0.1 + 0.2, 0.3)); // true
  1. 二进制和八进制:二进制以 0b 开头,八进制以 0o 开头
let b = 0b1010;
let o = 0o777;
let d = 100;
let x = 0xff;console.log(x);
  1. Number.isFinite 检测一个数值是否为有限数。

    console.log(Number.isFinite(100)); // true
    console.log(Number.isFinite(100 / 0)); // false
    console.log(Number.isFinite(Infinity)); // false
    
  2. Number.parseIntNumber.parseFloat ES6 给 Number 添加了 parseInt 方法,Number.parseInt 完全等同于 parseInt。将字符串转为整数,或者进行进制转换。Number.parseFloat 则等同于 parseFloat()

Number.parseInt(s, base);
  • s:待转换的字符串
  • base:进位制的基数
Number.parseInt === parseInt; // true
Number.parseFloat === parseFloat; // trueconsole.log(Number.parseInt('5211314love')); // 5211314
console.log(Number.parseFloat('3.1415926神奇')); // 3.1415926
  1. Number.isInteger() 判断一个数是否为整数
  2. Math.trunc() 将数字的小数部分抹掉
  3. Math.sign 判断一个数到底为正数 负数 还是零
  4. Number.isNaN() 检测一个数值是否为 NaN
console.log(Number.isInteger(5)); // true
console.log(Number.isInteger(2.5)); // falseconsole.log(Math.trunc(3.5)); // 3console.log(Math.sign(100)); // 1
console.log(Math.sign(0)); // 0
console.log(Math.sign(-20000)); // -1

18. 对象方法扩展

ES6 新增了一些 Object 对象的方法

18.1 Object.is()

Object.is() 方法判断两个值是否完全相同。Object.is 比较两个值是否严格相等,与 === 行为 基本一致,返回一个 Boolean 类型

Object.is(value1, value2);

Object.is() 方法判断两个值是否为同一个值。如果满足以下条件则两个值相等

  • 都是 undefined

  • 都是 null

  • 都是 true 或 false

  • 都是相同长度的字符串且相同字符按相同顺序排列

  • 都是相同对象(意味着每个对象有同一个引用)

  • 都是数字且
    ○ 都是 +0
    ○ 都是 -0
    ○ 都是 NaN
    ○ 或都是非零而且非 NaN 且为同一个值

与 == 运算不同。 == 运算符在判断相等前对两边的变量(如果它们不是同一类型)进行强制转换(这种行为的结果会将 “” == false 判断为 true),而 Object.is 不会强制转换两边的值
与 === 算也有不同,=== 运算符 (也包括 == 运算符) 将数字 -0 和 +0 视为相等,而将 Number.NaN 与 NaN 视为不相等

18.2 Object.assign

Object.assign 对象的合并,相当于浅拷贝

const config1 = {host: 'localhost',port: 3306,name: 'root',pass: 'root',test: 'test'
};
const config2 = {host: 'http://atguigu.com',port: 33060,name: 'atguigu.com',pass: 'iloveyou',test2: 'test2'
}
console.log(Object.assign(config1, config2));   // 有相同属性,后面的会覆盖前面的

18.3 Object.setPrototypeOf 和 Object.getPrototypeof

Object.setPrototypeOf 用于设置对象的原型对象
Object.getPrototypeof 用于获取对象的原型对象,相当于 proto

const school = {name: '尚硅谷'
}
const cities = {xiaoqu: ['北京','上海','深圳']
}
Object.setPrototypeOf(school, cities);  // 将school的隐式原型设置为cities
console.log(Object.getPrototypeOf(school));
console.log(school);

19. ES6 模块化

模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来

19.1 模块化的好处

模块化的优势有以下几点

  • 防止命名冲突

  • 代码复用

  • 高维护性

19.2 模块化规范产品

ES6 之前的模块化规范有(左侧规范,右侧产品)

  • CommonJS => NodeJS、Browserify

  • AMD => requireJS

  • CMD => seaJS

19.3 ES6 模块化语法

模块功能主要由两个命令构成

  • export 命令用于规定模块的对外接口

  • import 命令用于输入其他模块提供的功能

// m1.js
expert let school = 'w3c';expert function teach() {console.log("我们可以教给你开发技能");
}
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>ES6 模块化</title></head><body><script type="module">import * as m1 from "./src/js/m1.js";console.log(m1)</script></body>
</html>

1 模块导出数据语法

1 分别暴露
export let school = 'w3c';export function teach() {console.log("我们可以教给你开发技能");
}
2 统一暴露
let school = 'w3c';
function findJob(){console.log("我们可以帮助你找工作!!");
}export {school, findJob}
3 默认暴露
export default {school: 'w3c',change: function(){console.log("我们可以改变你!!");}
}

2 模块导入数据语法

1 通用导入方式
import * as m1 from './js/m1.js';
import * as m2 from './js/m2.js';
import * as m3 from './js/m3.js';m3.default.change()
2 解构赋值导入
import {school, teach} from "./src/js/m1.js";
import {school as guigu, findJob} from "./src/js/m2.js";
import {default as m3} from "./src/js/m3.js";
3. 简便方式导入,只能用于默认暴露
import m3 from "./src/js/m3.js";

3 ES6 使用模块化方式二

将文件导入都写进一个 app.js 文件中,然后在里面写入要导入的模块。app.js 中的内容如下

// 入口文件// 模块引入
import * as m1 from "./m1.js";
import * as m2 from "./m2.js";
import * as m3 from "./m3.js";// console.log(m1);
// console.log(m2);
// console.log(m3);// m1.teach();
// m2.findJob();
// m3.default.change();//修改背景颜色为粉色
import $ from 'jquery';// const $ = require("jquery");
$('body').css('background','pink');

在 index.html 中引入 app.js 文件内容:

<script src="./src/js/app.js" type="module"></script>

19.4 使用 babel 对模块化代码转换

有的浏览器不支持 ES6 语法,这时候就需要使用 babel 来将其转换成 ES5 等价语法

1. 安装工具

babel-cli babel命令行工具
babel-preset-env babel预设包,支持新的ES特性,转换为ES5语法
browserify/webpack 打包工具

npm i babel-cli babel-preset-env browserify(webpack) -D

2. 编译

// 局部安装使用 -d 目标目录
npx babel src/js -d dist/js --presets=babel-preset-env
// 全局安装可以省略 npx

3 打包

// -o 输出到的位置
npx browserify dist/js/app.js -o dist/bundle.js

此时再引入

<script src="dist/bundle.js"></script>

19.5 ES6 模块化引入 npm 安装的包

npm install jquery

再通过 import 导入即可

import $ from 'jquery'

三 ECMASript 7 新特性

1. Array.prototype.includes

includes 方法用来检测数组中是否包含某个元素,返回布尔类型值

2. 指数运算符

在 ES7 中引入指数运算符 **,用来实现幂运算,功能与 Math.pow(a, b) 结果相同

// includes   indexOf也可以判断
const mingzhu = ['西游记','红楼梦','三国演义','水浒传'];//判断
console.log(mingzhu.includes('西游记'));    //
console.log(mingzhu.includes('金瓶梅'));// **
console.log(2 ** 10);   // 1024
console.log(Math.pow(2, 10));

四 ECMAScript 8 新特性

1. async 和 await

asyncawait 两种语法结合可以让异步代码像同步代码一样(看起来是同步的,实质上是异步的)

先从字面意思理解,async 意为异步,可以用于声明一个函数前,该函数是异步的。await 意为等待,即等待一个异步方法完成

1.1 async

asyncfunction 变为成为 async 函数

  • async 内部可以使用 await,也可以不使用,因此执行这个函数时,可以使用 then 和 catch 方法
  • async 函数的返回值是一个 Promise 对象
  • Promise 对象的结果由 async 函数执行的返回值决定
async function funcName() {//statements
}
  • 函数体不 return 返回值,则 async 函数返回值为一个成功 fulfilled 的 Promise 对象,值为 undefined
let a = async function() {}
let res = a()
console.log(res) // Promise{<fullfilled>: undefined}
  • return 结果不是一个 Promise ,则 async 函数返回值为一个成功 fulfilledPromise 对象,状态值为这个内部返回值
let a = async function () {return 'hello'
}
let res = a()
console.log(res) // Promise{<fullfilled>: 'hello'}
  • 内部抛出错误,则 async 函数返回值为一个失败 reject 的 Promise 对象
let a = async function foo() {throw new Error('出错了')
}
a().catch(reason => {console.log(reason)
})
  • 若函数内部返回值是一个 Promise 对象,则 async 函数返回值的状态取决于这个 Promise 对象 是resolve 还是 reject
let a = async function () {return new Promise((resolve, reject) => {resolve("成功")})
}
a().then(value => {console.log(value)
})

1.2 await

await 相当于一个运算符,右边接一个值。一般为一个 Promise 对象,也可以是一个非 Promise 类型。

  • 当右接一个非 promise 类型,await 表达式返回的值就是这个值;
  • 当右接一个 promise 对象,则 await 表达式会阻塞后面的代码,等待当前 promise 对象 resolve 的值
  • 综合 async 和 await 而言
    • await 必须写在 async 函数中
    • await 右侧的表达式一般为 promise 对象
    • await 返回的是 promise 成功的值
    • await 的 promise 失败了就会抛出异常,需要使用 try-catch 捕获处理

Promise 使用链式调用解决了传统方式回调地狱的问题,而 async-await 又进一步优化了代码的可读性

// 创建 promise 对象
const p = new Promise((resolve, reject) => {// resolve("用户数据");reject("失败啦!"); // 设置状态跟值
})// await 要放在 async 函数中.
async function main() {try {let result = await p;  // 成功的值console.log(result);} catch (e) {console.log(e); // 失败的值}
}
// 调用函数
main(); // '失败'

1.3 综合应用-读取文件

需求:先后读取三个md文件
对于这种异步操作很容易想到使用 Promise

const fs = require('fs')let p = new Promise((resolve, reject) => {fs.readFile('./files/user.md', (err, data) => {if (err) reject(err)resolve(data)})
})p.then(value => {return new Promise((resolve, rejecet) => {fs.readFile('./files/order.md', (err, data) => {if (err) rejecet(err)resolve([value, data])})})
}, reason => {console.log(reason)
}).then(value => {return new Promise((resolve, reject) => {fs.readFile('./files/goods.md', (err, data) => {if (err) reject(err)value.push(data)resolve(value)})})
}, reason => {console.log(reason)
}).then(value => {console.log(value.join('\n'))
}, reason => {console.log(reason)
})

但是,使用 Promise 链式调用虽然避免了回调地狱,但这种链式调用过多难免引起代码复杂,看起来不直观。可以使用 async 和 await 方法优化

//1. 引入 fs 模块
const fs = require("fs");//读取『为学』
function readWeiXue() {return new Promise((resolve, reject) => {fs.readFile("./resources/为学.md", (err, data) => {if (err) reject(err);resolve(data);})})
}function readChaYangShi() {return new Promise((resolve, reject) => {fs.readFile("./resources/插秧诗.md", (err, data) => {if (err) reject(err);resolve(data);})})
}function readGuanShu() {return new Promise((resolve, reject) => {fs.readFile("./resources/观书有感.md", (err, data) => {if (err) reject(err);resolve(data);})})
}//声明一个 async 函数
async function main(){let weixue = await readWeiXue(); // 获取为学内容let chayang = await readChaYangShi(); // 获取插秧诗内容let guanshu = await readGuanShu();   // 获取观书有感console.log(weixue.toString());console.log(chayang.toString());console.log(guanshu.toString());
}main()

1.4 综合应用-封装ajax

axios 返回的就是一个 promise 对象

// 发送 AJAX 请求, 返回的结果是 Promise 对象
function sendAJAX(url) {return new Promise((resolve, reject) => {const x = new XMLHttpRequest();x.open('GET', url);x.send();x.onreadystatechange = function () {if (x.readyState === 4) {if (x.status >= 200 && x.status < 300) {resolve(x.response);}reject(x.status);}}})
}//promise then 方法测试
// sendAJAX("https://api.apiopen.top/getJoke").then(value=>{
//     console.log(value);
// }, reason=>{})// async 与 await 测试  axios
async function main(){//发送 AJAX 请求let result = await sendAJAX("https://api.apiopen.top/getJoke");let tianqi = await sendAJAX('https://www.tianqiapi.com/api/?version=v1&city=%E5%8C%97%E4%BA%AC&appid=23941491&appsecret=TXoD5e8P')console.log(tianqi);
}main();

2. Object.values 和 Object.entries

  • Object.values() 方法返回一个给定对象的所有可枚举属性值的数组
  • Object.keys(),只是前者返回属性值,后者返回键值组合的数组
  • Object.entries() 方法返回一个给定对象自身可遍历属性 [key,value] 的数组,可以使用 for…of 遍历
let obj = {a: 1,b: {1:2},c: [1,2,3]
}console.log(Object.values(obj))    // [1, {1: 2}, [1,2,3]]
console.log(Object.keys(obj))   // ['a', 'b', 'c']const obj = {a: 1, b: 2, c: 3};console.log(Object.entries(obj))    // [ [ 'a', 1 ], [ 'b', 2 ], [ 'c', 3 ] ]
for (let [k, v] of Object.entries(obj)) {   console.log(k, v)
}
  • Object.getOwnPropertyDescriptors() 获取对象属性的描述对象
console.log(Object.getOwnPropertyDescriptors(school));const obj = Object.create(null, {name: {//设置值value: 'school',//属性特性writable: true,configurable: true,enumerable: true}
});

JavaScript 精选:哪些能提高开发效率的es6 新语法糖相关推荐

  1. vscode php插件_JS之 提高开发效率的Visual Studio Code插件

    阅读本文约需要9分钟 大家好,我是你们的导师,我每天都会在这里给大家分享一些干货内容(当然了,周末也要允许老师休息一下哈).上次老师跟大家分享了JS之 小技巧的知识,今天跟大家分享下JS之 提高开发效 ...

  2. 第三节:快速编译TypeScript,提高开发效率

    上一节我们成功把TypeScript 编译安装好了,接下来我们就看看编译器怎么用起来. 在写代码之前,我们先来选个开发工具,支持TypeScript 的IDE有很多,其中就包括了webstorm,VS ...

  3. 猿团YTFramework UI框架正式发布 提高开发效率

    由猿团开发的全新移动端UI框架:YTFramework UI(以下简称YTF UI)正式推出,即日起,开发者即可在YTF UI 页面进行框架的下载和使用. YTF UI是一款前端UI框架,以rem作为 ...

  4. vscode自动补全插件c语言,一些提高开发效率的VSCode必备插件(分享),vscode代码补全插件...

    一些提高开发效率的VSCode必备插件(分享)提高开发效率的虚拟代码的一些重要插件(分享),本文推荐一些VSCode插件来提高效率.有一定的参考价值,有需要的朋友可以参考一下,希望对大家有帮助.Vis ...

  5. 10个提高开发效率的Vue3常用插件(快来收藏)

    本篇文章给大家总结分享几个好用的 Vue 插件,可以帮助开发者提高开发效率.解决移动端各种滚动场景需求,希望对大家有所帮助! 1.vue-multiselect-next Vue.js 的通用选择/多 ...

  6. “六神”——技术提高开发效率的一个方案

    这个方案并不是我在系统设计方面的最早一次尝试.但它在提高开发效率方面,是效果最为显著的一个方案. 简介 "六神"框架提供了一套简单而通用的.从Web层到数据库操作(增加单个数据.删 ...

  7. 什么样的鼠标对程序员最有用,超级提高开发效率

    目录 学会使用鼠标左边的两个按键,提高开发效率 .今天给大家分享一个鼠标小技巧,先看下图 这两个键非常有用,可能很多人还不知道怎么用他,加上很多公司都配置很普通的鼠标,根本没有这个两个按钮. 那这两个 ...

  8. 能够提高开发效率的Eclipse实用操作

    概要: 工欲善其事,必先利其器.对于程序员来说,Eclipse便是其中的一个"器".本文会从 Eclipse快捷键和实用技巧这两个篇章展开介绍.Eclipse快捷键用熟后,不用鼠标 ...

  9. 如何通过组件化提高开发效率?

    在软件开发过程中,大到业务模块的划分,小到技术组件的开发,都属于组件化的思考范畴内.很多时候我们到网上搜索「组件化」关键词,都只会看到关于前端组件化的资料,而对于后台开发组件化的资料却很少,那这是不是 ...

最新文章

  1. Delphi 中的颜色常量及效果图
  2. 使用Gensim来实现Word2Vec和FastText
  3. tableau和powerbi的联系和区别
  4. iOS之深入解析Runtime的Method-Swizzling方法交换的妙用和底层原理
  5. 无法打开包括文件:“mysql..h”: No such file or directory
  6. 一文搞懂 什么是CPU上下文?为什么要切换?如何减少切换?
  7. 设置linux文件系统密码,busybox 文件系统设置 登陆 login 密码 password shadow
  8. ConsumerNetworkClient 分析
  9. 大神齐聚,算法大赛复赛晋级名单揭晓!
  10. 鸿蒙系统华为mate10,从3899跌至1040,2K分辨率+4000mAh,可升级鸿蒙系统
  11. 利用树莓派完成POS58打印机的无驱动打印(初学者)
  12. A公司物流配送安全风险管理现状
  13. graphpad如何换柱状图与折线图能否混合一起_excel柱状图加折线图组合怎么做,原来是这样的...
  14. appStore苹果退款通知
  15. Smart Thief 问题
  16. 【web前端开发】HTML知识点超详细总结
  17. MySQL - java.sql.SQLException: Data truncated for column ‘xx‘ at row 1
  18. unity应用实例——从头撸一个全新的FPS游戏(5)
  19. “很抱歉,出现错误,Word不能启动(2)。”解决方法(转载),2023-3-3
  20. 淘宝天猫商家运营,运营能力提升,淘宝竞争对手的分析,如何学习对手的优势运营方法

热门文章

  1. 2019微信公开课 同行With Us 听课笔记及演讲全文
  2. 网络安全通识全解|第10期 安全上网你要懂得的事
  3. 如何高效迅速的进行CodeReview
  4. mysql update set_mysql update语句的用法详解
  5. TPMS胎压传感器烧录器
  6. 超级电容锂电池混合储能Simulink仿真
  7. xilinx gt ip 位置约束
  8. 诺顿ghost使用教程
  9. 学无止境的CSS(xHTML+CSS技巧教程资源大全)
  10. Linux查看端口占用情况的命令