摘要:以前现在创建一个叫做的变量,值是数组中第一个对象中键的值。以前用的时候使用链式来处理这种连续请求。一个可以一个,并且等待结果以后再进行下一步。并且一请求到就立即打印结果,并不等待后续的请求完成。
String Template Strings
连接String更方便直观。使用反引号包括要生成的String,使用${}包括具体变量。
var name = "Yixuan"; var email = "yixuan124@gmail.com"; var title = "Student"; //以前 var msg = "Welcome! Your " + title + " is " + name + ", contact: " + email + "."; //现在 var msg = `Welcome! Your ${title} is ${name}, contact: ${email}.` //Welcome! Your name is Yixuan, contact: yixuan124@gmail.com.Tagged Templates
在模版字符串前调用自定函数,来定制模版字符串的解析方式。这个函数的第一个函数包含一个字符串值的数组,其余的参数是一系列的$表达式的引用变量,可以用...操作来把这些参数当成一个数组。
这个例子中我们的自定函数formatCurrency将字符串中的数字加上了$符号并保留两位小数。
var amount = 4.2; var msg = formatCurrency`The total for your order is ${amount}.` function formatCurrency(strings, ...values) { var str = ""; //console.log(strings); for (let i = 0; i < strings.length; i++) { str += strings[i]; if( i < values.length){ console.log(typeof values[i]); if(typeof values[i] == "number") { str += `$${values[i].toFixed(2)}`; }else { str += values[i]; } } } return str; } console.log(msg); //The total for your order is $12.30.String Padding & String Trimming
JS标准库中现在自带给字符串两边加内容和删减空格的方法。
padStart给字符串左边加内容,padEnd给字符串右边加内容。
var str = "Hello"; str.padStart(5); // "Hello" str.padStart(8) // " Hello" str.padStart(8, "*"); // "***Hello" str.padStart(8, "12345"); // "123Hello" str.padStart(8, "ab"); // abaHello" str.padEnd(8) // "Hello " str.padEnd(8, "*") // "Hello***" str.padEnd(8, "ab"); // "Helloaba"
trimStart去除左边空格, trimEnd去除右边空格。
var str = " some stuff "; str.trim(); // "some stuff" str.trimStart(); // "some stuff " str.trimEnd(); // " some stuff"Destructuring
有时我们get到了一个很大的JSON对象,我们需要把里面的一些值分配到变量当中。解构让这个操作更方便。
看一个例子。
var tmp = getSomeRecords(); //tmp是一个拥有两个对象的数组。 //以前 var first = tmp[0]; var second = tmp[1]; var firstName = first.name; var firstEmail = first.email !== undefined ? first.email : "no email"; var secondName = second.name; var secondEmail = second.email !== undefined ? first.email : "no email"; //现在 var [ {// 创建一个叫做firstName的变量,值是数组中第一个对象中name键的值。 name: firstName, // 创建一个叫做firstEmail的变量,值是数组中第一个对象中email键的值,如果没有这个键则使用默认值“no email"。 email: firstEmail = "no email" }, { name: secondName, email: secondEmail = "no email" } ] = tmp;
注意在这个例子中,赋值等号左边的[],这个中括号不代表数组,而代表一种解构赋值的pattern模式。还有要注意的是像上面这个例子的email的默认值只会在检测到undefined的时候才会被使用,如果值是null,不会触发使用默认值。
看一个更简单的例子。
function data(){ return [1,2,3]; } // 以前 var tmp = data(); var first = tmp[0]; var second = tmp[1]; var third = tmp[2]; //现在 var [ first, second, third ] = data();
如果左边的变量比右边的值多,多余的变量的值就会是undefined。如果左边的变量比右边的值少,多余的值会被忽略。
如果我们要在一个变量里多赋几个值呢?
data = [1,2,3,4,5]; var [ first, second, third, ...fourth ] = data; //这里fourth是[4,5];
如果值不够
data =[1,2,3]; var [ first, second, third, ...fourth ] = data; //这里fourth是空数组[];
有的时候我们需要交换变量的值,用解构也更方便。
var x = 10; var y = 20; //以前 var tmp = x; x = y; y = tmp; //现在 ] [y,x] = [x,y];
有的时候我们将一个数组传入函数的时候,我们只需要它的前三个元素,我们也可以使用解构,在函数参数声明的时候就做到这步。
function data([ first, second, third ]) { }
解构赋值如果出现赋值错误,和普通赋值一样,也会报错。
var data = null; var [first, second] = data; //TypeError function foo([first,second]) } { ... } foo(data);//传入null //TypeError
这个时候我们需要Graceful Fallback(降级,向下兼容)
var data = null; var [first, second] = data || []; //不报错 function foo([first,second] = []) } { ... } //不报错
嵌套解构
var data = [1,[2,3],4]; var [ first, [ second, third ], fourth ] = data;Object Destructuring
有的时候我们有一个默认的对象,但是我们需要根据一个新传过来的对象,来创建一个新对象。举个例子,我们知道的表单信心有name,wechat,phone,gender等属性(键名),但是有时表单会有新的属性。这是我们可以用解构赋值来很好的创建出一个新对象,来传到后端或传到数据库。
function makeObject({ name = "default name", wechat = "default wechat", phone = "default phone", gender = "none", ...otherProps } = {}) { return { name, wechat, phone, gender, ...otherProps } } const obj = { name: "wyx", wechat: "weixin", gender: "male", age:"22", year:"2019" } const newObj = makeObject(obj); console.log(newObj); /* { name: "wyx", wechat: "weixin", phone: "default phone",//没有的属性使用默认值 gender: "male", age: "22", year: "2019" } */Array Array.find()
找到数组中相应的值,如果有就返回这个值,没有就undefined。
var arr = [{a:1},{a:2}]; var res = arr.find(v => v && v.a > 1); console.log(res); // {a:2} res = arr.find(v => v && v.a > 10); console.log(res); // undefinedArray.findIndex()
找到相应值的index
var arr = ["a","b","c","d"]; var res = arr.findIndex(v => v && v == "c"); console.log(res); // 2 res = arr.findIndex(v => v && v == "x"); console.log(res); // -1Array.includes()
用来代替以前的Array.indexOf(xxx) != -1
var arr = [10,20,30,40]; //以前 if(arr.indexOf(30) != -1){ console.log("exist!"); } //现在 if(arr.includes(30)) { console.log("exist!"); } //exist!Array.flat()
摊开数组,可以根据传入参数改变具体摊开的层数。默认摊开一层。
var nestedArray = [1,2,[3,4],[5,[6,7]]]; nestedValues.flat(0); //[1,2,[3,4],[5,[6,7]]] nestedValues.flat(); //default 1 //[1,2,3,4,5,[6,7]] nestedValues.flat(2); //[1,2,3,4,5,6,7];Array.flatMap()
flatMap只能摊开一层,如果需要更多层,需要分开使用map()和flat().
[1,2,3,4,5,6].flatMap(v => { if (v % 2 == 0) { return [v, v * 2]; } else { return []; } }) //[2,4,4,8,6,12]Iterator Built-in Iterable
Iterator简单来说,就是我们用next()来遍历一个集合。
在ES6中,String, Array, TypedArray,Map, Set是默认iterable的。
var str = "Hi" //在string上使用iterator var it1 = str[Symbol.iterator](); //这里Symbol.iterator是str对象的一个属性,我们通过[Symbol.iterator]获取到这个对象的iterator然后把它赋给it1。 it1.next(); // { value: "H", done: false} it2.next(); // { value: "i", done: false} it3.next(); // { valye: undefinedn done:true} var arr = ["H","i"]; //在Array上使用iterator var it2 = arr[Symbol.iterator](); it2.next(); // {value : "H", done: false} it2.next(); // {value : "i", done: false} it2.next(); // {value : undefined, done: true}Declarative Iterators
for of 循环其实就是使用了iterator
var str = "Hello"; var it = str[Symbol.iterator](); //在for loop中使用iterator for(let v of it){ console.log(v); } //效果和直接使用for loop是一样的 for (let v of str) { console.log(v); }
...符号也使用iterator
var str ="Hello"; var letters = [...str]; console.log(letters); // ["H","e","l","l","o"]Object类型没有iterator
我们在js中最常使用的对象类型,没有默认的iterator,我们需要自己定义一个。
var obj = { a : 1, b : 2, c : 3 } for (let v of obj) { console.log(v); } // TypeError! //想要使用for of循环的时候出现了错误 //定义iterator属性 obj[Symbol.iterator] = function(){ let keys = Object.keys(this); let index = 0; return { next: () => { if(index < keys.length){ return { done : false, value : keys[index++] } }else { return { done : true, value : undefined } } } }; } console.log([...obj]); //["a","b","c"]Generators Generators
function *generate() { yield 1; yield 2; yield 3; return 4; } var it = generate(); it.next(); // {value: 1, done : false} it.next(); // {value: 2, done : false} it.next(); // {value: 3, done : false} it.next(); // {value: 4, done : true} console.log([...generate()]); // [1,2,3]
一个使用生成器的例子,这里我们给luckyNumbers对象一个我们自定义的生成器函数叫lucky,然后在调用这个生成器的时候使用...操作符来iterate这个生成器,打印1-30之间6的倍数。
var luckyNumbers = { *lucky({ start = 0, end = 100, step = 1 } = {}) { for (let i = start; i <= end; i+= step) { yield i; } } }; console.log(`My lucky numbers are: ${ [...luckyNumbers.lucky({ start: 6, end: 30, step: 4 })] }`) //My lucky numbers are: 6,10,14,18,22,26,30Async Await Async出现的历史
这里有一个例子,我们先请求当前当前用户,获得用户数据以后,又请求当前用户所下过订单和进行中的订单的例子。
以前用Promise的时候,使用链式then()来处理这种连续请求。
fetchCurrentUser() .then(function onUser(user) { //获得当前用户 return Promise.all([ //用Promise.all来做两个请求,返回的还是一个promise,如果有一个请求中有一个reject则都reject fetchArchivedOrders( user.id ), fetchCurrentOrders (user.id) ]); })
后来我们有人不再用链式then()来处理多个请求。而是用generator来获得多个请求的response。一个generator可以yield一个promise,并且等待yield结果以后再进行下一步。但是这个方法一般要使用第三方库的一种runner函数进行,像Co,Koa都有。runner函数的作用就是在yield的时候等待结果resolve,然后再往下iterate,往下yield。
runner(function *main() { var user = yield fetchCurrentUser(); var [ archivedOrders, currentOrders ] = yield Promise.all([ fetchArchivedOrders( user.id ), fetchArchivedOrders( user.id ) ]) });
其实上面这个例子里的yield关键词,已经很像await关键词了,所以后来JS官方就推出了Async Await关键词,不再需要用第三方库的runner函数。
async function main() { var user = await fectchCurrentUser(); var [archiveOrders, currentOrders] = await Promise.all([ fetchArchiveOrders(user.id), fetchCurrentOrders(user.id) ]); return archiveOrders + currentOrders; }
这里有个例子,我们同时请求三个file,但是保证打印结果是按顺序打印,也没有undefined。并且一请求到就立即打印结果,并不等待后续的请求完成。
function getFile(file) { return new Promise(function(resolve){ fakeAjax(file,resolve); }); } async function loadFiles(files) { var prs = files.map(getFile); //用map同时做三个请求 for (let pr of prs) { console.log(await pr); } //在for loop中加入await关键词,来确保按顺序打印,也不会undefined。 } loadFiles(["files","file2","file3"]);async await problems
async await也有一些问题
await只能应对Promise
Starvation
promise会在时间循环中排进microtask,会造成饥饿陷阱,这里不多写。
cancelation
Async函数是没有办法被手动取消的,比如一个request要下载巨大的文件,async函数过程就会一直进行
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/104670.html
摘要:声明之函数作用域和全局作用域。块级作用域不能重复声明临时性死区等特性用来解决变量存在的种种问题。块级作用域终于在外面访问不到了。一些常量声明使用声明的变量名全部大写。 ES5之前javascript语言只有函数作用域和全局作用域,使用var来声明变量,var声明的变量还存在变量提升使人困惑不已。我们先来复习一下ES5的var声明,再对比学习let和const 。 var var声明之函...
摘要:结合工作中使用情况,简单对进行一些复习总结,包括常用的语法,等,以及短时间内要上手需要重点学习的知识点不同工作环境可能有一些差别,主要参考链接是阮一峰的博客以及外文博客阮老师大部分文章是直接翻译的这个博客简介先说一下,是一个标准化组织,他们 结合工作中使用情况,简单对es6进行一些复习总结,包括常用的语法,api等,以及短时间内要上手需要重点学习的知识点(不同工作环境可能有一些差别),...
摘要:的暑期实习面试到现在差不多都结束了,算下来自己也投了十几家简历,经历的差不多十场笔试,现场和电话面试也差不多有五六家公司。阿里三面三面不知道是不是交叉面,不过这次面试面试官说他是北京的之前都是杭州。 2017的暑期实习面试到现在差不多都结束了,算下来自己也投了十几家简历,经历的差不多十场笔试,现场和电话面试也差不多有五六家公司。虽然最后只拿到两个offer,所幸是自己期待的公司,下面从...
阅读 1453·2019-08-30 15:44
阅读 1915·2019-08-30 14:07
阅读 2843·2019-08-30 13:56
阅读 2304·2019-08-29 17:06
阅读 1274·2019-08-29 14:13
阅读 2044·2019-08-29 11:28
阅读 3189·2019-08-26 13:56
阅读 1916·2019-08-26 12:11