ES8

3、ES8

1. async函数和await表达式

acync:

  • async函数的返回值为promise对象
  • promise对象的结果由async函数执行的返回值决定
async function fn() {
  // 1.return的不是promise对象,则返回的结果就是成功的promise对象
  return '123'; // [[PromiseState]]: "fulfilled"  [[PromiseResult]]: "123"
  return        // [[PromiseState]]: "fulfilled"  [[PromiseResult]]: undefined
  // 2.抛出错误,返回的结果是一个失败的promise对象
  throw '出错';  // [[PromiseState]]: "rejected"   [[PromiseResult]]: "出错"
  // 3.return的是一个promise对象,则返回的结果由return的那个pomise决定
  return new Promise((resolve, reject) => {
    resolve('成功');  // [[PromiseState]]: "fulfilled"  [[PromiseResult]]: "成功"
    reject('失败');   // [[PromiseState]]: "rejected"   [[PromiseResult]]: "失败"
  });
}
const result = fn();
console.log(result);

await表达式:

  • await必须写在async函数中
  • await右侧的表达式一般为promise对象
  • await返回的是promise成功的值
  • await的promise失败了就会抛出异常,需要通过try…catch捕获处理
const p = new Promise((resolve, reject) => {
  resolve('成功');
  reject('失败');
})
async function main() {
  try {
    // p成功的情况下执行
    let result = await p;
    console.log(result);  // 成功
  } catch(e) {
    // p失败的情况下执行
    console.log(e); // 失败
  }
}
main();

async和await结合读取文件

const fs = require('fs');
function getOne() {
  return new Promise((resolve, reject) => {
    fs.readFile('文件地址1', (err, data) => {
      if(err) reject(err);
      resolve(data);
    });
  })
}
function getTwo() {
  return new Promise((resolve, reject) => {
    fs.readFile('文件地址2', (err, data) => {
      if(err) reject(err);
      resolve(data);
    });
  })
}
function getThree() {
  return new Promise((resolve, reject) => {
    fs.readFile('文件地址3', (err, data) => {
      if(err) reject(err);
      resolve(data);
    });
  })
}
async function main() {
  let one = await getOne();
  let two = await getTwo();
  let three = await getThree();
  console.log(one.toString());
  console.log(two.toString());
  console.log(three.toString());
}
main();

async和await结合封装AJAX请求

// 发送AJAX请求,返回的结果是promise对象
function sendAJAX(url) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open("GET", url);
    xhr.send();
    xhr.onreadystatechange = function() {
      if(xhr.readyState === 4) {
        if(xhr.status >= 200 && xhr.status < 300) {
          resolve(xhr.response);
        } else {
          reject(xhr.status);
        }
      }
    }
  })
}
// promise.then 方法测试
sendAJAX("https://....").then(value => {
  console.log(value);
}, reason => {
  console.log(reason);
})
// async await测试
async function main() {
  try {
    let result = await sendAJAX("https://....");
  	console.log(result);
  } catch(e) {
    console.log(e);
  }
}

2. Object.values 和 Object.entries

  • Object.values() 方法返回一个给定对象的所有可枚举属性值的数组
  • Object.entries() 方法返回一个给定对象自身可遍历属性(key, value)的数组
const person = {
  name: 'zhangsan',
  age: [11,16],
  like: ['play', 'eat', 'speak']
}
Object.keys(person); // ["name", "age", "like"]
Object.values(person); // ["zhangsan", Array(2), Array(3)]
												// 0: "zhangsan"
												// 1: (2) [11, 16]
												// 2: (3) ["play", "eat", "speak"]
Object.entries(person); //  [Array(2), Array(2), Array(2)]
													// 0: (2) ["name", "zhangsan"]
													// 1: (2) ["age", Array(2)]
													// 2: (2) ["like", Array(3)] 
// 创建Map
console.log(new Map(Object.entries(person))); 
// Map(3) {"name" => "zhangsan", "age" => Array(2), "like" => Array(3)}
		// 0: {"name" => "zhangsan"}
		// 1: {"age" => Array(2)}
		// 2: {"like" => Array(3)}
Object.keys(obj)

参数:要返回其枚举自身属性的对象

返回值:一个表示给定对象的所有可枚举属性的字符串数组,不包括属性名为Symbol值的属性 enumerable: false不可枚举

  1. 如果属性名的类型是Number,那么Object.keys返回值是按照key从小到大排序
  2. 如果属性名的类型是String,那么Object.keys返回值是按照属性被创建的时间升序排序。
  3. 如果属性名的类型是Symbol,那么逻辑同String相同
  4. 负数是作为字符串String处理的,也是按照定义时候的顺序
// 处理对象,返回可枚举的属性数组
let person = {name:"张三",age:25,address:"深圳",getName:function(){}}
Object.keys(person); 		// ["name", "age", "address","getName"]
// 处理数组,返回索引值数组
let arr = [1,2,3,4,5,6];
Object.keys(arr); 			// ["0", "1", "2", "3", "4", "5"]
// 处理字符串,返回索引值数组,因为String对象有可提取的属性
let str = "saasd字符串";
Object.keys(str); 			// ["0", "1", "2", "3", "4", "5", "6", "7"]
// 常用技巧
let person = {name:"张三",age:25,address:"深圳",getName:function(){}}
Object.keys(person).map((key)=>{
  return person[key] // 获取到属性对应的值,做一些处理  ["张三", 25, "深圳", ƒ]
}) 
// 返回的对象没有任何可提取的属性,所以返回空数组
Object.keys(123);	// []
var obj = {name: 'zyp', age: 18};
Object.defineProperty(obj, 'like', {
	enumerable: false, // 不可枚举
	value: 'reading'
})
Object.defineProperty(obj, Symbol(), {
	value: 'symbol'
})
var properNameArr = Object.keys(obj);  // properNameArr结果为["name", "age"]

Object.keys被调用时背后发生了什么

  • 调用ToObject(O)将结果赋值给变量obj

  • 调用EnumerableOwnPropertyNames(obj, "key")将结果赋值给变量nameList

  • 调用CreateArrayFromList(nameList)得到最终的结果

1、将参数转换成Object(ToObject(O))

  • Undefined | 抛出TypeError
  • Null | 抛出TypeError
  • Boolean | 返回一个新的 Boolean 对象
  • Number | 返回一个新的 Number 对象
  • String | 返回一个新的 String 对象
  • Symbol | 返回一个新的 Symbol 对象
  • Object | 直接将Object返回

2、获得属性列表(EnumerableOwnPropertyNames(obj, "key")

针对Object.keys这个API来说,获取属性列表中最重要的是调用了内部方法OwnPropertyKeys得到ownKeys。其实也正是内部方法OwnPropertyKeys决定了属性的顺序。

关于OwnPropertyKeys方法ECMA-262中是这样描述的:

O的内部方法OwnPropertyKeys被调用时,执行以下步骤(其实就一步):

  1. Return ! OrdinaryOwnPropertyKeys(O).

OrdinaryOwnPropertyKeys是这样规定的:

  1. 声明变量keys值为一个空列表(List类型)
  2. 把每个Number类型的属性,按数值大小升序排序,并依次添加到keys
  3. 把每个String类型的属性,按创建时间升序排序,并依次添加到keys
  4. 把每个Symbol类型的属性,按创建时间升序排序,并依次添加到keys
  5. keys返回(return keys

上面这个规则不光规定了不同类型的返回顺序,还规定了如果对象的属性类型是数字,字符与Symbol混合的,那么返回顺序永远是数字在前,然后是字符串,最后是Symbol。

Object.keys({
  5: '5',
  a: 'a',
  1: '1',
  c: 'c',
  3: '3',
  b: 'b'
})	// ["1", "3", "5", "a", "c", "b"]
// 属性的顺序规则中虽然规定了Symbol的顺序,但其实Object.keys最终会将Symbol类型的属性过滤出去。(原因是顺序规则不只是给Object.keys一个API使用,它是一个通用的规则)

3、将List类型转换为Array得到最终结果(CreateArrayFromList( elements )

将List类型的属性列表转换成Array类型非常简单:

  1. 先声明一个变量array,值是一个空数组
  2. 循环属性列表,将每个元素添加到array
  3. array返回

上面介绍的排序规则同样适用于下列API:

  1. Object.entries
  2. Object.values
  3. for...in循环
  4. Object.getOwnPropertyNames
  5. Reflect.ownKeys
Object.values()

Object.values方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历( enumerable )属性的键值。

var obj = { 100: 'a', 2: 'b', 7: 'c' };
Object.values(obj); 	// ["b", "c", "a"]
// 上面代码中,属性名为数值的属性,是按照数值大小,从小到大遍历的,因此返回的顺序是b、c、a。
// Object.values只返回对象自身的可遍历属性。
var obj = Object.create({}, {p: {value: 42}});
Object.values(obj) // []
//上面代码中,Object.create方法的第二个参数添加的对象属性(属性p),如果不显式声明,默认是不可遍历的。Object.values不会返回这个属性。
// Object.values会过滤属性名为 Symbol 值的属性。
Object.values({ [Symbol()]: 123, foo: 'abc' });	// ['abc']

// 如果Object.values方法的参数是一个字符串,会返回各个字符组成的一个数组。
Object.values('foo');	// ['f', 'o', 'o']
// 上面代码中,字符串会先转成一个类似数组的对象。字符串的每个字符,就是该对象的一个属性。因此,Object.values返回每个属性的键值,就是各个字符组成的一个数组
// 如果参数不是对象,Object.values 会先将其转为对象。由于数值和布尔值的包装对象,都不会为实例添加非继承的属性。所以,Object.values 会返回空数组。
Object.values(42); 		// []
Object.values(true); 	// []
Object.entries()

Object.entries方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历( enumerable )属性的键值对数组。

var obj = { foo: 'bar', baz: 42 };
Object.entries(obj);	// [ ["foo", "bar"], ["baz", 42] ]
//	除了返回值不一样,该方法的行为与Object.values基本一致。

//	如果原对象的属性名是一个 Symbol 值,该属性会被省略。将来可能会有Reflect.ownEntries()方法,返回对象自身的所有属性。
Object.entries({ [Symbol()]: 123, foo: 'abc' });	// [ [ 'foo', 'abc' ] ]

Object.entries的基本用途是遍历对象的属性。

var obj = { foo: 'bar', baz: 42 };
for (let [k, v] of Object.entries(obj)) {
    console.log(`${JSON.stringify(k)}: ${JSON.stringify(v)}`);
}			// "foo": "bar"    // "baz": 42

Object.entries方法的一个用处是,将对象转为真正的Map结构。

var obj = { foo: 'bar', baz: 42 };
var map = new Map(Object.entries(obj)); // Map(2) {"foo" => "bar", "baz" => 42}
map // Map { foo: "bar", baz: 42 }

自己实现Object.entries方法,非常简单。

function* entries(obj) {
    for (let key of Object.keys(obj)) {
        yield [key, obj[key]];
    }
}
//  非 Generator 函数的版本
function entries(obj) {
    let arr = [];
    for (let key of Object.keys(obj)) {
        arr.push([key, obj[key]]);
    }
    return arr;
}

3. Object.getOwnPropertyDescriptors

返回指定对象所有自身属性的描述对象

const person = {
  name: 'zhangsan',
  age: [11,16],
  like: ['play', 'eat', 'speak']
}
Object.getOwnPropertyDescriptors(person);  
// {name: {…}, age: {…}, like: {…}}
	// age: {value: Array(2), writable: true, enumerable: true, configurable: true}
	// like: {value: Array(3), writable: true, enumerable: true, configurable: true}
	// name: {value: "zhangsan", writable: true, enumerable: true, configurable: true}
	// __proto__: Object
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值