ES6、ES7...的常用语法(2)

Set和Map数据结构

ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。

const s = new Set();

[2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));

for (let i of s) {
  console.log(i);}
// 2 3 5 4


// 去除数组的重复成员
[...new Set(array)]

ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。

const m = new Map();
const o = {p: 'Hello World'};

m.set(o, 'content')
m.get(o) // "content"


//注意,只有对同一个对象的引用,Map 结构才将其视为同一个键。这一点要非常小心。
const map = new Map();

map.set(['a'], 555);
map.get(['a']) // undefined

Map 结构的实例有以下属性和操作方法。

//size属性返回 Map 结构的成员总数。
const map = new Map();
map.set('foo', true);
map.set('bar', false);
map.size // 2

//set方法设置键名key对应的键值为value,然后返回整个 Map 结构。如果key已经有值,则键值会被更新,否则就新生成该键。
m.set(262, 'standard')     // 键是数值

//get方法读取key对应的键值,如果找不到key,返回undefined。
m.get(hello)  // Hello ES6!

//has方法返回一个布尔值,表示某个键是否在当前 Map 对象之中。
m.has(262)           // true

//delete方法删除某个键,返回true。如果删除失败,返回false。
m.delete(undefined)

//clear方法清除所有成员,没有返回值。
map.clear()

Proxy

Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。

var proxy = new Proxy({}, {
  get: function(target, propKey) {
    console.log(target,propKey) //{} "time"
    return 35; 
  }});

console.log(proxy.time) // 35

set()方法用来拦截某个属性的赋值操作,可以接受四个参数,依次为目标对象、属性名、属性值和 Proxy 实例本身,其中最后一个参数可选。

假定Person对象有一个age属性,该属性应该是一个不大于 200 的整数,那么可以使用Proxy保证age的属性值符合要求。

let validator = {
  set: function(obj, prop, value) {
    if (prop === 'age') {
      if (!Number.isInteger(value)) {
        throw new TypeError('The age is not an integer');
      }
      if (value > 200) {
        throw new RangeError('The age seems invalid');
      }
    }

    // 对于满足条件的 age 属性以及其他属性,直接保存
    obj[prop] = value;
  }};

let person = new Proxy({}, validator);

person.age = 100;

person.age // 100
person.age = 'young' // 报错
person.age = 300 // 报错

Promise

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。

有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。一旦状态改变,就不会再变,任何时候都可以得到这个结果。

const promise = new Promise(function(resolve, reject) {
  // ... some code
  var b = false
  if (b){
    resolve('調用成功');
    console.log(2); //还是会继续执行的,不受resolve的影响
  } else {
    reject('調用失敗');
}});
  
//then方法的第一个参数是resolved状态的回调函数,第二个参数(可选)是rejected状态的回调函数
promise.then(function(value) {
  // success
  console.log('成功',value)
}, function(error) {
  // failure
  console.log('失敗',error)
});

promise.catch((error)=>{
  console.log('出问题了')
})

//finally()方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。该方法是 ES2018 引入标准的。
promise.finally(()=>{
  console.log('无论如何都会执行')
})

Promise.all()的状态由p1、p2、p3决定,分成两种情况。

(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。

(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

 Promise.all([p1, p2, p3]).then(function (posts) {
  // ...
}).catch(function(reason){
  // ...
});

Promise.any()只要有一个成功,就返回fulfilled
Promise.race()只要有一个返回,有以第一个返回的状态为准

for … of

ES6 借鉴 C++、Java、C# 和 Python 语言,引入了for…of循环,作为遍历所有数据结构的统一的方法。a

const arr = ['red', 'green', 'blue'];

for(let v of arr) {
  console.log(v); // red green blue
}

JavaScript 原有的for…in循环,只能获得对象的键名,不能直接获取键值。ES6 提供for…of循环,允许遍历获得键值。

var arr = ['a', 'b', 'c', 'd'];

for (let a in arr) {
  console.log(a); // 0 1 2 3
}

for (let a of arr) {
  console.log(a); // a b c d
}


// 字符串
let str = "hello";
for (let s of str) {
  console.log(s); // h e l l o
}

Set 结构遍历时,返回的是一个值,而 Map 结构遍历时,返回的是一个数组,该数组的两个成员分别为当前 Map 成员的键名和键值。

let map = new Map().set('a', 1).set('b', 2);

for (let pair of map) {
    console.log(pair);
  }
// ['a', 1]
// ['b', 2]

for (let [key, value] of map) {
     console.log(key + ' : ' + value);
  }
// a : 1
// b : 2

并不是所有类似数组的对象都具有 Iterator 接口,一个简便的解决方法,就是使用Array.from方法将其转为数组。

console.log(Array.from('foo'));
// expected output: Array ["f", "o", "o"]

let arrayLike = { length: 2, 0: 'a', 1: 'b' };
// 报错
for (let x of arrayLike) {
  console.log(x);
  }
// 正确
for (let x of Array.from(arrayLike)) {
  console.log(x); // a b
  }

对于普通的对象,for…of结构不能直接使用,会报错,必须部署了 Iterator 接口后才能使用。但是,这样情况下,for…in循环依然可以用来遍历键名。

let es6 = {
  edition: 6,
  committee: "TC39",
  standard: "ECMA-262"};

for (let e in es6) {
  console.log(e);}
// edition
// committee
// standard

//不能用of
for (let e of es6) {
  console.log(e);
  }
// TypeError: es6[Symbol.iterator] is not a function

//of要替换成下面的操作
let arrayLike = { length: 2, 0: 'a', 1: 'b' };
for (var key of Object.keys(arrayLike)) {
  console.log(key + ':' + arrayLike[key]);
  //0:a  1:b length:2
}

//或者使用 Generator 函数将对象重新包装一下
function* entries(obj) {
  for (let key of Object.keys(obj)) {
    yield [key, obj[key]];
}}

for (let [key, value] of entries(obj)) {
  console.log(key, '->', value);}
// a -> 1
// b -> 2
// c -> 3

Generator 函数的语法

形式上,Generator 函数是一个普通函数,但是有两个特征。一是,function关键字与函数名之间有一个星号;二是,函数体内部使用yield表达式,定义不同的内部状态(yield在英语里的意思就是“产出”)。

function* helloWorldGenerator() {
  yield 'hello';
  yield 'world';
  return 'ending';
  }

var hw = helloWorldGenerator();


hw.next()
// { value: 'hello', done: false }

hw.next()
// { value: 'world', done: false }

hw.next()
// { value: 'ending', done: true }

hw.next()
// { value: undefined, done: true }
//第四次调用,此时 Generator 函数已经运行完毕,next方法返回对象的value属性为undefined,done属性为true。以后再调用next方法,返回的都是这个值。

asyn 函数

ES2017 标准引入了 async 函数,使得异步操作变得更加方便。它就是 Generator 函数的语法糖。

const fs = require('fs');

const readFile = function (fileName) {
  return new Promise(function (resolve, reject) {
    fs.readFile(fileName, function(error, data) {
      if (error) return reject(error);
      resolve(data);
    });
  });
};

const gen = function* () {
  const f1 = yield readFile('/etc/fstab');
  const f2 = yield readFile('/etc/shells');
  console.log(f1.toString());
  console.log(f2.toString());
};
  
 //上面代码的函数gen可以写成async函数,就是下面这样。
const asyncReadFile = async function () {
  const f1 = await readFile('/etc/fstab');
  const f2 = await readFile('/etc/shells');
  console.log(f1.toString());
  console.log(f2.toString());
};
  //一比较就会发现,async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await,仅此而已。

在asyn里面的await使函数可以顺序的执行完成

function timeout(ms) {
  return new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
}
async function testAsyn() {
  console.log(1)
  await timeout(1000).then(()=>{
    console.log('1000的then')
  });
  console.log(2)
  await timeout(3000).then(()=>{
    console.log('3000的then')
  });
  console.log(3)
  return '按顺序1234执行完成!';
}
testAsyn().then(function (result) {
  console.log(4)
  console.log(result);
});

上面函数有await打印的顺序

1
1000的then
2
3000的then
3
4
按顺序1234执行完成!

上面函数没有await打印的顺序

1
2
3
4
按顺序1234执行完成!
1000的then
3000的then

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值