We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
本次的ES6语法的汇总总共分为上、中、下三篇,本篇文章为中篇。
汇总上篇文章请戳这里--谈谈ES6语法(汇总上篇)
好了,我们直奔中篇的内容~
数组扩展运算符(spread)是三个点(...)。它好比rest参数的逆运算,将一个数组转为用空格分隔的参数序列。
...
console.log(...[1, 2, 3]); // 1 2 3 console.log(1, ...[2, 3, 4], 5); // 1 2 3 4 5
⚠️rest参数是运用在函数参数上的,将函数参数转换为数组的形式,如下:
function fn(...values) { console.log(values); // ['jia', 'ming'] } fn('jia', 'ming');
下面我们结合数组扩展运算符和rest参数来实现一个类似call的方法call2操作:
call
Function.prototype.call2 = function(context, ...args){ // 这里使用到rest参数 context = context || window; // 因为传递过来的context有可能是null context.fn = this; // 让fn的上下文为context const result = context.fn(...args); // 这里使用了数组扩展运算符 delete context.fn; return result; // 因为有可能this函数会有返回值return } var job = 'outter teacher'; var obj = { job: 'inner teacher' }; function showJob() { console.log(this.job); } showJob(); // outter teacher showJob.call2(obj); // inner teacher
复习一下,我们把var job = 'outter teacher'改为let job = 'outter teacher'后,showJob()会输出什么?
var job = 'outter teacher'
let job = 'outter teacher'
showJob()
答案是undefined。在前一篇中也提到过,ES6语法声明的变量是不会挂载在全局对象上的~
undefined
Array.from方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(对象包括ES6新增的数据结构Set和Map)。
Array.from
两类对象
// 类数组转化成数组 let arrayLike = { '0': 'a', '1': 'b', '2': 'c', length: 3 } // ES5的写法 var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c'] // ES6的写法 let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
Array.of()方法用于将一组值,转换为数组。
Array.of()
let arr = Array.of(2, 3, 'reng'); console.log(arr); // [2, 3, 'reng'] console.log(arr.pop()); // reng
Array.of基本上可以弥补Array()或new Array()带来的因为参数个数导致的不同行为。Array.of基本上可以替代它们两个了。
Array.of
Array()或new Array()
Array.of(); // [] Array.of('reng'); // ['reng'] Array.of(2, 'reng'); // [2, 'reng']
数组中还有其它有用的方法:
include(el)
[1, [2, [3]]].flat(Infinity); // [1, 2, 3]
有这么一个需求:将数组[[2, 8], [2], [[4, 6], 7, 6]]转成一维且元素不重复的数组。
将数组[[2, 8], [2], [[4, 6], 7, 6]]转成一维且元素不重复的数组。
我们的实现方案如下:
let arr = [[2, 8], [2], [[4, 6], 7, 6]]; console.log([...new Set(arr.flat(Infinity))]); // [2, 8, 4, 6, 7]
ES6允许字面量定义对象时,把表达式放在方括号内:
let lastWord = 'last word'; const a = { 'first word': 'hello', [lastWord]: 'world', ['end'+'symbol']: '!' }; a['first word'] // 'hello' a[lastWord] // 'world' a['last word'] // 'world' a['endsymbol'] // '!'
上面整理数组扩展内容的时候,提到了数组的扩展运算符。ES2018将这个运算符引入了对象~
ES2018
let z = { a: 3, b: 4 }; let n = { ...z }; // 关键点 n // { a: 3, b: 4 }
===
const obj = { foo: 'bar', baz: 42 }; Object.entries(obj) // [ ["foo", "bar"], ["baz", 42] ]
Set翻译出来就是集合,有元素唯一性的特点。
Set
在数组去重的场景上很有用处:
// 去除数组的重复成员 [...new Set(array)] // 如 console.log([...new Set([2, 2, 3, 2])]); // [2, 3]
顺便添加下es5的数组去重的方法吧:
ES5实现: [1,2,3,1,'a',1,'a'].filter(function(ele,index,array){ return index===array.indexOf(ele)})
需要留意的Set属性和方法有以下:
WeakSet结构与Set类似,也是有不重复元素的集合。但是它和Set有两个区别:
WeakSet
WeakSet对象中只能存放对象引用, 不能存放值, 而Set对象都可以.
WeakSet中对象中存储的对象值都是被弱引用的, 如果没有其他的变量或属性引用这个对象值, 则这个对象值会被当成垃圾回收掉. 正因为这样, WeakSet 对象是无法被枚举的, 没有办法拿到它包含的所有元素。
WeakSet中
var ws = new WeakSet(); var obj = {}; var foo = {}; ws.add(window); ws.add(obj); ws.has(window); // true ws.has(foo); // false, 对象 foo 并没有被添加进 ws 中 ws.delete(window); // 从集合中删除 window 对象 ws.has(window); // false, window 对象已经被删除了 ws.clear(); // 清空整个 WeakSet 对象
WeakSet 没有size属性,没有办法遍历它的成员。
Map对象保持键值对。任何值(对象或者原始值)都可以作为一个键或一个值。
Map
Object和Map的比较:
Object
Symbols
如果你需要“键值对”的数据结构,Map比Object更合适。
const set = new Set([ // 数组转换为map ['foo', 1], ['bar', 2] ]); const m1 = new Map(set); m1.get('foo') // 1 const m2 = new Map([['baz', 3]]); const m3 = new Map(m2); m3.get('baz') // 3
Map拥有的属性和方法和Set相似,多出了些:
WeakMap结构与Map结构类似,也是用于生成键值对的集合。但是有两点区别:
WeakMap
属性方法啥的跟Map差不多,就是没有了size和forEach,因为其是不可枚举的。
size
forEach
Promise是异步编程的一种解决方案,比传统的解决方案“回调函数和事件”更合理和更强大。
Promise
Promise对象有以下两个特点:
对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。
pending
fulfilled
rejected
一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种情况:从pending变成fulfilled(fulfilled也称resolved)和从pending变成rejected。
fulfilled(fulfilled也称resolved)
const promise = new Promise(function(resolve, reject) { // ...some code if(/* 异步操作成功 */) { resolve(value); } else { reject(error); } })
参数resolve和reject是两个函数,由JavaScript引擎提供,不用自己部署。
resolve
reject
Promise实例生成之后,可以使用then方法分别指定resolved状态和rejected状态的回调函数。
then
resolved
promise.then(function(value) { // success }, function(error) { // failure });
我们来粘贴个简单例子:
function timeout(ms) { return new Promise((resolve, reject) => { setTimeout(resolve, ms, 'done'); }); } timeout(100).then((value) => { console.log(value); // 100ms后输出'done' });
嗯~我们顺道来复习下setTimeout的第三个参数。哦😯,不,是第三个,第四个...
setTimeout
var timeoutID = scope.setTimeout(function[, delay, param1, param2, ...]);
function
delay
param1, ..., paramN
那么,到这里你理解了上面的例子为什么在100ms后输出done了嘛💨
100ms
done
详细的setTimeout信息,请戳MDN的setTimeout。
简单的例子看完了,看下我们在工作中使用得比较多的请求接口的例子:
const getJSON = function(url) { const promise = new Promise(function(resolve, reject){ const handler = function() { if(this.readyState !== 4) { return; } if(this.status === 200) { resolve(this.response); // this.response作为参数传给then中的json } else { reject(new Error(this.statusText)); } }; const client = new XMLHttpRequest(); client.open('GET', url); client.onreadystatechange = handler; client.responseType = 'json'; client.setRequestHeader('Accept', 'application.json'); client.send(); }); return promise; }; getJSON('/post.json').then(function(json) { console.log('Contents: '+ json); }, function(error) { console.log('error happen ', error); });
Promise.prototype.catch方法是.then(null, rejection)或.then(undefined, rejection)的别名,用于指定发生错误时的回调函数。
Promise.prototype.catch
.then(null, rejection)
.then(undefined, rejection)
p.then((val) => console.log('fulfilled:', val)) .catch((err) => console.log('rejected', err)); // promise中任何一个抛出错误,都会被最后一个catch捕获 // 等同于 p.then((val) => console.log('fulfilled:', val)) .then(null, (err) => console.log('rejected:', err));
Promise.prototype.finally()方法(其不接受任何参数)用于指定不管Promise对象最后状态如何,都会执行的操作。该方法是 ES2018 引入标准的。
Promise.prototype.finally()
语法:
promise .then(result => {···}) .catch(error => {···}) .finally(() => {···});
构造函数方法Promise.all方法用于将多个Promise实例,包装成一个新的Promise实例。
Promise.all
const p = Promise.all([p1, p2, p3]);
上面代码中,Promise.all方法接受一个数组作为参数,p1, p2, p3都是Promise实例。如果不是会调用Promise.resolve方法,具体看文档。
p1, p2, p3
Promise.resolve
// 生成一个Promise对象的数组 const promises = [2, 3, 5, 7, 11, 13].map(function (id) { return getJSON('/post/' + id + ".json"); }); Promise.all(promises).then(function (posts) { // ... }).catch(function(reason){ // ... });
上面代码中,promises是包含 6 个 Promise 实例的数组,只有这6个实例的状态都变成fulfilled,或者其中有一个变为rejected,才会调用Promise.all方法后面的回调函数。
promises
⚠️注意,如果作为参数的Promise实例,自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.all()的catch方法。所以使用Promise.all()别手痒在每个实例promise内添加错误捕获。
catch
Promise.all()
需求:使用promise改写下面的代码,使得输出的期望结果是每隔一秒输出0, 1, 2, 3, 4, 5,其中i < 5条件不能变
0, 1, 2, 3, 4, 5
i < 5
for(var i = 0 ; i < 5; i++){ setTimeout(function(){ console.log(i); },1000) } console.log(i);
我们直接上使用promise改写的代码吧~
const tasks = []; // 存放promise对象 for(let i = 0; i < 5; i++){ tasks.push(new Promise((resolve) => { setTimeout(() => { console.log(i); resolve(); }, 1000 * i); })); } Promise.all(tasks).then(() => { setTimeout(() => { console.log(tasks.length); }, 1000); }); // 每隔一秒输出 0, 1, 2, 3, 4, 5
更多的内容,请戳我的博客进行了解,能留个star就更好了💨
The text was updated successfully, but these errors were encountered:
No branches or pull requests
本次的ES6语法的汇总总共分为上、中、下三篇,本篇文章为中篇。
汇总上篇文章请戳这里--谈谈ES6语法(汇总上篇)
好了,我们直奔中篇的内容~
数组扩展
数组扩展运算符
数组扩展运算符(spread)是三个点(
...
)。它好比rest参数的逆运算,将一个数组转为用空格分隔的参数序列。下面我们结合数组扩展运算符和rest参数来实现一个类似
call
的方法call2操作:复习一下,我们把
var job = 'outter teacher'
改为let job = 'outter teacher'
后,showJob()
会输出什么?答案是
undefined
。在前一篇中也提到过,ES6语法声明的变量是不会挂载在全局对象上的~Array.from()
Array.from
方法用于将两类对象
转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(对象包括ES6新增的数据结构Set和Map)。Array.of()
Array.of()
方法用于将一组值,转换为数组。Array.of
基本上可以弥补Array()或new Array()
带来的因为参数个数导致的不同行为。Array.of
基本上可以替代它们两个了。数组中还有其它有用的方法:
include(el)
方法相似有这么一个需求:
将数组[[2, 8], [2], [[4, 6], 7, 6]]转成一维且元素不重复的数组。
我们的实现方案如下:
对象扩展
属性名表达式
ES6允许字面量定义对象时,把表达式放在方括号内:
对象的扩展运算符
上面整理数组扩展内容的时候,提到了数组的扩展运算符。
ES2018
将这个运算符引入了对象~对象中某些新增的方法
===
行为基本一致Set和Map数据结构
Set
Set
翻译出来就是集合,有元素唯一性的特点。在数组去重的场景上很有用处:
顺便添加下es5的数组去重的方法吧:
需要留意的Set属性和方法有以下:
WeakSet
WeakSet
结构与Set
类似,也是有不重复元素的集合。但是它和Set有两个区别:WeakSet
对象中只能存放对象引用, 不能存放值, 而Set
对象都可以.WeakSet中
对象中存储的对象值都是被弱引用的, 如果没有其他的变量或属性引用这个对象值, 则这个对象值会被当成垃圾回收掉. 正因为这样, WeakSet 对象是无法被枚举的, 没有办法拿到它包含的所有元素。WeakSet 没有size属性,没有办法遍历它的成员。
Map
Map
对象保持键值对。任何值(对象或者原始值)都可以作为一个键或一个值。Object和Map的比较:
Object
的键只能是字符串或者Symbols
,但一个Map
的键可以是任意值,包括函数、对象、基本类型。Map
中的键值是有序的,而添加到对象中的键则不是。因此,当对它进行遍历时,Map
对象是按插入的顺序返回键值。Map
在涉及频繁增删键值对的场景下会有些性能优势`。如果你需要“键值对”的数据结构,
Map
比Object
更合适。Map拥有的属性和方法和Set相似,多出了些:
WeakMap
WeakMap
结构与Map
结构类似,也是用于生成键值对的集合。但是有两点区别:WeakMap
只接受对象作为键名(null除外),不接受其他类型的值作为键名。WeakMap
的键名所指向的对象,不计入垃圾回收机制。和WeakSet
相似啦。属性方法啥的跟
Map
差不多,就是没有了size
和forEach
,因为其是不可枚举的。Promise对象
Promise
是异步编程的一种解决方案,比传统的解决方案“回调函数和事件”更合理和更强大。Promise
对象有以下两个特点:对象的状态不受外界影响。
Promise
对象代表一个异步操作,有三种状态:pending
(进行中)、fulfilled
(已成功)和rejected
(已失败)。一旦状态改变,就不会再变,任何时候都可以得到这个结果。
Promise
对象的状态改变,只有两种情况:从pending
变成fulfilled(fulfilled也称resolved)
和从pending
变成rejected
。用法
参数
resolve
和reject
是两个函数,由JavaScript引擎提供,不用自己部署。Promise
实例生成之后,可以使用then
方法分别指定resolved
状态和rejected
状态的回调函数。我们来粘贴个简单例子:
嗯~我们顺道来复习下
setTimeout
的第三个参数。哦😯,不,是第三个,第四个...function
是你想要在到期时间(delay
毫秒)之后执行的函数。delay
是可选语法,表示延迟的毫秒数。param1, ..., paramN
是可选的附加参数,一旦定时器到期,它们会作为参数传递给function
那么,到这里你理解了上面的例子为什么在
100ms
后输出done
了嘛💨详细的
setTimeout
信息,请戳MDN的setTimeout。简单的例子看完了,看下我们在工作中使用得比较多的请求接口的例子:
catch方法
Promise.prototype.catch
方法是.then(null, rejection)
或.then(undefined, rejection)
的别名,用于指定发生错误时的回调函数。finally方法
Promise.prototype.finally()
方法(其不接受任何参数)用于指定不管Promise
对象最后状态如何,都会执行的操作。该方法是 ES2018 引入标准的。语法:
Promise.all
构造函数方法
Promise.all
方法用于将多个Promise
实例,包装成一个新的Promise
实例。上面代码中,
Promise.all
方法接受一个数组作为参数,p1, p2, p3
都是Promise
实例。如果不是会调用Promise.resolve
方法,具体看文档。上面代码中,
promises
是包含 6 个Promise
实例的数组,只有这6个实例的状态都变成fulfilled
,或者其中有一个变为rejected
,才会调用Promise.all
方法后面的回调函数。Promise
实例,自己定义了catch
方法,那么它一旦被rejected
,并不会触发Promise.all()
的catch
方法。所以使用Promise.all()
别手痒在每个实例promise内添加错误捕获。一道练手题
需求:使用promise改写下面的代码,使得输出的期望结果是每隔一秒输出
0, 1, 2, 3, 4, 5
,其中i < 5
条件不能变我们直接上使用promise改写的代码吧~
参考和后话
本次的ES6语法的汇总总共分为上、中、下三篇,本篇文章为中篇。
更多的内容,请戳我的博客进行了解,能留个star就更好了💨
The text was updated successfully, but these errors were encountered: