时间匆匆, 转眼毕业已经快两年了。 最为一个前端小白的我, 现在怎么说也是灰色的了吧? 前段时间一直有个想法: 想把自己学到的前端知识点整理下,感觉这样有助于自己基础的巩固。 所以才有个今天这个js知识点回顾文章。 好吧,废话少说了, 先从javascript开席吧!
前言:
毕业的时候本来不是做前端的。 作为一个后台培训出来的应届生。 匆匆培训java、html、 css、 java2ee 、ssh等一大堆东西。第一家公司是来上海做后台。 记得有一次项目中老大说让我整理个页面, 当时懵逼了都。 什么? 让我写个ajax ? !虽然培训过前端方面的知识, 但是也只是匆匆而过,有个大概的了解。 没办法只能硬着头皮上网上找资料啊。 心想如果做不出来,会不会被开除啊?( 我想每个实习期的童鞋都有这样的经历吧 哈哈...)这就算是我第一次真正接触前端。 嗯 ,没毛病。
正文:
1、 JavaScript简介
JavaScript 和java 没个卵的关系。 ECMAScript就是对实现该标准规定的各个方面内容的语言的描述。
JavaScript实现了ECMAScript。 所以什么es5 es6 es7 是ECMAScript5 6 7 的简写。 至于其它概念,大概看下就行。(只是本人自己的看法)!
JavaScript在当前五个主要浏览器( IE、 Firefox、 Chrome、 Safari和 Opera) 中 都得到了不同程度的支持。 所以才有了兼容性的问题。 但人类的脚步是向前的。 比如babel 编译器解决了这种差异。统一编译成es5。呵呵哒!
2、 推荐在javaScript 中使用 "use strict" 。why ? 让我就举个栗子:
"use strict"; //在正常模式中,如果一个变量没有声明就赋值,默认是全局变量。严格模式禁止这种用法,全局变量必须显式声明。v = 1; // 报错,v未声明for (i = 0; i < 2; i++) { // 报错,i未声明}//因此, 严格模式下, 变量都必须先用var命令声明, 然后再使用。function f() { return this; //非严格模式下 因为"this"指向全局对象,返回全局对象}function f() { "use strict"; //这行代码看起来像是字符串,而且也没有赋值给任何变量,但其实它是一个编译指示(pragma),// 用于告诉支持的 JavaScript引擎切换到严格模式return this; //严格模式下 this的值为undefined,}复制代码
严格模式下方法入参不能有重复定义的变量、 对象不能有重复的属性。。。
而且有时候 "use strict"可以节省函数执行的时间。
推荐语句以一个分号结尾。(以前做的一个vuejs项目 eslint 不能用; 结尾 结果我们公司有个大大牛就问了 你们js为什么语句不以分号结尾都添加上 加上!!!。。。。。好吧 结果我们把eslint关了哎。。。)
3、 js 基本数据类型
字符串 string var const let
数值 Number Number()
真假 Boolean new Boolean()
数组 Array new Array() | []
对象 Object new Object | {}
NaN isNaN(a) //转成Number类型进行判断 so alert(isNaN("10")); //false(可以被转换成数值 10)
var num2 = Number(""); //0 var num4 = Number(true); //1 var num3 = Number("000011"); //11复制代码
what you find that ?
so not use Number use parseInt()
var num2 = parseInt(""); // NaN var num1 = parseInt("1234blue");// 1234 刚发现 666var num4 = parseInt(22.5); // 22 var num5 = parseInt("070"); // 56(八进制数)var num6 = parseInt("70"); // 70(十进制数)var num7 = parseInt("0xf"); // 15(十六进制数)复制代码
false 的8个值: ''
0、 - 0、 NaN、 false 、null、 undefined、 newBoolean()
问个问题:
[] === '' []== ''复制代码
结果是什么? why?
typeof 返回的是字符串, 有六种可能:
"number"、
"string"、
"boolean"、
"function"、
"undefined"、
"object": {
[],
{}
}
其中 null类型 typeof null === "object" 复制代码
so 判断变量是数组还是对象的时候 要过滤null。
eg:
if (isWaitting && isWaitting instanceof Array) {}复制代码
举个例子吧:
var shallowCopy = function(obj) { //一个浅拷贝方法应该知道为什么有这个方法吧 (数组、对象中地址引用的锅)if (typeof obj != 'object') return;var newObj = obj instanceof Array ? [] : {};for (var key in obj) {if (obj.hasOwnProperty(key)) {newObj[key] = obj[key];}}return newObj;}复制代码
再来个深拷贝: //记得gitHub 上有一个deep-assign npm可以install哦 有需要的大家可以搜下
var deepCopy = function(obj) {if (typeof obj !== 'object') return; //null NaN Mathvar newObj = obj instanceof Array ? [] : (!obj ? null : {});for (var key in obj) {if (obj.hasOwnProperty(key)) {newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) :obj[key];}}return newObj;}复制代码
4、 在html引入js要注意的事项
肯定要写在 < script > < /script>里面喽!没话说的。如果浏览器不支持js的话 那用
<noscript ><p> 本页面需要浏览器支持( 启用) JavaScript。 </noscript>
我是至今也没见过浏览器显示这个的。 除非你把浏览器设置了不支持js语法。
这样当我没说!!js一般引入的位置是在body后面而不是header里面。 因为浏览器渲染的过程中是单线程的。 当js加载完成并执行后才能继续往下加载别的。
一句话概括吧: 就是你他妈的js加载多的话,入口页面渲染完成所用的时间过多, 体验不要。 嗯, 这个也引发了后面的前端优化什么的。 有点人说尽量不再js中改变dom节点的更改、 减少http的请求、
使用img snipe、 根据路由懒加载依赖的文件、 外部引用js文件的时候加defer( 这个属性的用途是表明脚本在执行时不会影响页 面的构造。也就是说, 脚本会被延迟到整个页面都解析完毕后再运行。 因此, 在 < script > 元素中设置 defer 属性, 相当于告诉浏览器立即下载,但延迟执行。)复制代码
拓展:
同样与 defer 类似,async 只适用于外部脚本文件, 并告诉浏览器立即下载文件。 但与 defer 不同的是, 标记为 async 的脚本并不保证按照指定它们的先后顺序执行。 例如:
在以上代码中, 第二个脚本文件可能会在第一个脚本文件之前执行。 因此, 确保两者之间互不依赖 非常重要。
指定 async 属性的目的是不让页面等待两个脚本下载和执行, 从而异步加载页面其他内容。
为此, 建议异步脚本不要在加载期间修改 DOM。 异步脚本一定会在页面的 load 事件前执行,但可能会在 DOMContentLoaded 事件触发之前或之 后执行。
支持异步脚本的浏览器有Firefox 3.6、 Safari5 和 Chrome5、 来个运算符吧
var a = 0;a++;++a;复制代码
老生常谈了
var a = 0;a + +1 输出什么?//1 why?'' + 11 + '''1' + '2'1 + true输出什么?var num1 = 2;var num2 = 20;var num3 = --num1 + num2; // 输出什么?0.1 + 0.2 // 输出什么? 应该怎么做才能不丢失精度呢?考虑复制代码
6、 Boolean
以前常常看到人们判断一个变量是否为空 是否是没定义
if( a != null && typeof a != 'undefined') {}复制代码
忘了上面的‘ false 的8个值’ 了嘛? 今天以后就可以这样写
if(a) {} // a 不能是 0 -0 NaN '' false null undefined复制代码
特殊情况特殊对待
!!!a //强制转化a的类型为Boolean类型复制代码
追加:
a && b //短路运算 a如果为false 那么b不用判断了 懒!var c = a || 'fd' //默认赋值 a如果为false 那么c赋值为‘fd’ Infinity //了解下就行 我都没遇到过 无穷大--Infinity //无穷大的负数 你说是什么呢?for (;;) { // 无限循环 doSomething(); } for (true) { // 无限循环 doSomething(); } continue; break; //只能使用在循环遍历中 // foreach() map()里能用不 ?思考下 复制代码
7、 函数function
函数中的结束: return;
函数中没有java的重载。 只有替换
函数中没有类但能模拟类
//es5
var superClass = function() {this.name = null;}superClass.prototype.setName = function(name) {this.name = name;}superClass.prototype.getName = function() {return this.name;}var superC = new superClass();superC.setName('fd');superC.getName();var subClass = superClass.prototype; //继承subClass.prototype.mackSound = function() {this.name = '电风扇';}复制代码
//es6
class superClass2 {constructor() {this.name = name;}getName() {return this.name;}setName(name) {this.name = name;}show() {console.log(this.name);}}var as = new superClass2();as.setName('fdsf');as.show();class superClass3 extends superClass2 { //继承}var sdf = new superClass3();复制代码
8、闭包
(function sd() { console.log(12) })()//自动执行函数 复制代码
function adds() {var something = "ssh";var another = [1, 2, 3];function doSomething() {alert(something);}function doAnother() {alert(another.join(","));}return { doSomething: doSomething,doAnother: doAnother};}var fn = adds();fn.doSomething(); // coolfn.doAnother(); // 1 ! 2 ! 3//私有数据变量something和another,以及doSomething()和doAnother() 两个内部函数,//它们的语法作用域(而这就是闭包)也就是foo() 的内部作用域。复制代码
var a = (function() {var i = 0;return function() {return i++;}})()复制代码
var b = (function(name) {var i = 0;function identify() {alert(name.toUpperCase());}function add() {return i++;}return{identify:identify,add:add}})('ssh')复制代码
9、上下文执行环境 作用域
var a = 10;function sum(b) {return a + b;}function add() {var a = 20;var c = sum(30);return c;}add(); //40复制代码
why?为什么不是50呢?我的理解是:当函数没有执行前,函数中的变量就已经确定指向。比如sum()中 当没有调用add()方法的时候,sum()方法里的a已经的指针已经指向了全局作用域下定义的var a = 10;而非调用时候的var a = 20;
总结:函数创建的时候 就已经确定了作用域 . 要到创建这个函数的那个作用域中取值——是“创建”,而不是“调用”,切记切记.
上面描述的只是跨一步作用域去寻找。如果跨了一步,还没找到呢?——接着跨!——一直跨到全局作用域为止。要是在全局作用域中都没有找到,那就是真的没有了。
这个一步一步“跨”的路线,我们称之为——作用域链。
我们拿文字总结一下取自由变量时的这个“作用域链”过程:(假设a是自由量)
第一步,现在当前作用域查找a,如果有则获取并结束。如果没有则继续;
第二步,如果当前作用域是全局作用域,则证明a未定义,结束;否则继续;
第三步,(不是全局作用域,那就是函数作用域)将创建该函数的作用域作为当前作用域;
第四步,跳转到第一步。
var x = {name:'ssh',age:18}var fn = function(){console.log(this);console.log(this.name);}fn.call(x);//fn.apply(x)复制代码
//当一个函数被call和apply调用时,this的值就取传入的对象的值
既然说到了call apply 那就再继续说点吧
用call()apply() 可以强制指定this的指向。那么this又是什么玩意呢?代表当前作用域本身。在全局作用域下
在函数块级作用域下
这样应该明白了吧
有一天看到了一个这种写法
var arr = [1,2,4,5,7,34]Math.max.call(null,1,2,4,5,7,34) //34Math.max.apply(null,arr) //34复制代码
从上面可以看出两个东西:
1、call apply 接收参数的格式不同 怎么不同? 自己看
2、重新定义了Math.max函数的this指向
Es6:Math.max(...arr) //了解下就行。
上下文执行环境:就是当前函数执行时候所处的环境 环境应该都知道 java开发前都要先配置jre jdk开发环境 咱们的javascript中 函数运行时候也要有自己的环境。当一个函数执行完成后
当前上下文执行环境就会被销毁。至于涉及到堆栈方面的知识,技术有限,说不出来。。。。。想知道这样面的知识可以自行google。10.地址引用遇到的坑
地址引用的数据类型有:array object
Var arr = [1,2];
自己理解:变量arr 中其实放的不是数据 1,2 。寄存的只是一个hash地址。该地址指向存放[1,2]的数据池。如果重新给arr赋值 arr = [1,3] 则arr指针重新指向了另一个数据池[1,3] 。
但是:当 var arr= [1,2] ;arr.push(4); 这时候指针是不变化的。变化的是指针定向的数据池里的数据。这点要注意。
记得有个面试题如下:
var arr = [1, 2, 3];var c = arr;arr = [1, 2];console.log(c); //[1, 2, 3]arr.push(4);console.log(arr); //[1, 2,4]console.log(c); //[1, 2, 3]var arr2= [1, 2, 3];var c2 = arr2;arr2.push(4);console.log(arr2); //[1, 2, 3,4]console.log(c); //[1, 2, 3]var obj = [{ name: 'ssh' }, { name: 'ssh2'}]var obj2 = [];obj.forEach((item, index) => {item.name == 'ssh' ? obj2.push(item) : false;})obj2[0].name = 'ssh2222';console.log(obj) // 有变化嘛如果有 why?复制代码
11、Math
常用的几种:
Math.abs() //返回数的绝对值。
Math.floor() //对数进行下舍入。 地板 懂?
Math.ceil() //对数进行上舍入。 天花板 懂?
Math. //返回 x 和 y 中的最高值。
Math.min(x,y)// 返回x 和 y 中的最低值。
Math. //返回 x 的 y 次幂。
Math. // 返回 0 ~ 1 之间的随机数。
Math. //把数四舍五入为最接近的整数。
Math.trunc(2.643) //2 截取小数点前面的数字
12、Date
Var a = new Date();本地全部时间格式:toLocaleString(); // "2017/11/16 下午4:27:09"a.toLocaleDateString() //"2017/11/16"toLocaleTimeString() // "下午4:27:09"getFullYear() //2017getTime()getTime() 返回从 1970 年 1 月 1 日至今的毫秒数。//+new Date()getDay()//如何使用 getDay() 和数组来显示星期几,而不仅仅是数字 //周日 =>0 ?复制代码
13、 Array 方法
主要几点就行了:
push pop 都是从数组后面开始处理数据的 (栈)shift unshift 从头开始 (队列)slice() 相当于重新定义了个数组 即不同的指针splice() //从数组中移除一个或多个数组,并用新的item代替他们 返回被替换的数组var a = ['a','b','c','d'];var b = a.splice(1,3,'f');a// ["a", "f"]b// ["b", "c","d"]复制代码
14、数组去重的正确编写姿势(面试很爱问!)
//使用数组的indexOf()方法可以很简单的达到目的。Array.prototype.unique = function() {// 创建一个新的临时数组,用于保存输出结果var n = []; // 遍历当前数组for (var i = 0; i < this.length; i++) {// 如果当前数组的第i个元素已经保存进了临时数组,那么跳过,否则把当前项push到临时数组里面if (n.indexOf(this[i]) == -1) n.push(this[i]);// if (!n.includes(this[i]))n.push(this[i]);}return n;}复制代码
最快姿势
//把已经出现过的元素通过下标的形式存入一个Object内。下标的引用的实现原理利用的是哈希算法,要比用indexOf()搜索数组快的多。Array.prototype.unique = function() {// n为hash表,r为临时数组var n = {}, r = [];for (var i = 0; i < this.length; i++) {// 如果hash表中没有当前项if (!n[this[i]]) {// 存入hash表n[this[i]] = true;// 把当前数组的当前项push到临时数组里面r.push(this[i]); }}return r;}复制代码
但从耗时的角度来讲,这是最优的一种解决方式。但是从内存占用角度来说,这并不是最优的,因为多了一个hash表。这就是所谓的空间换时间(世间安得双全法?)。
中庸姿势 //推荐
Array.prototype.unique = function() {this.sort();var re = [this[0]];for (var i = 1; i < this.length; i++) {if (this[i] !== re[re.length - 1]) {re.push(this[i]);}}return re;}复制代码
// [...new Set([1,1,3,4,3,56,6])] 最简单的方法复制代码
既然提到了new Set() 那么就延伸点别的吧
删除数组中指定的项:
Array.prototype.$remove = function (v) {const index = this.indexOf(v) //this代表数组本身if (index !== -1) this.splice(index, 1)return this;}const arr = [1, 2, 3]arr.$remove(2) //下标从1开始复制代码
Array.prototype.$delete = function (v){var set = new Set(this);// this 代表该数组本身set .delete(v);return [...set]}var arr = [1, 2, 3]arr.remove(2)// [1, 3]复制代码
es6 新添加了很多方法
如foreach、map 、filter 、reduce 、objectAssign 、copy、 includes 、indexof 、Array.isArray() 、Array.from() new Set() new Map() 等 。
在此不做详细的说明,想了解的可以自行google。
15、单线程中的异步
我们还经常遇到setTimeout(fn,0)这样的代码,0秒后执行又是什么意思呢?是不是可以立即执行呢?
答案是不会的,setTimeout(fn,0)的含义是,指定某个任务在主线程最早可得的空闲时间执行,意思就是不用再等多少秒了,只要主线程执行栈内的同步任务全部执行完成,栈为空就马上执行。
举例说明:
console.log('先执行这里');setTimeout(() => {console.log('执行啦1')},10);setTimeout(() => {console.log('执行啦2')},0);console.log('最后执行这里');复制代码
16、异步(重点 面试还是爱问!)
Promise:异步
下面是一个Promise对象的简单例子。
function timeout(ms) {return new Promise((resolve, reject) => {setTimeout(resolve, ms, 'done');});}timeout(100).then((value) => {console.log(value); //'done'});复制代码
上面代码中,timeout方法返回一个Promise实例,表示一段时间以后才会发生的结果。过了指定的时间(ms参数)以后,Promise实例的状态变为resolve,就会触发then方法绑定的回调函数。
Promise 实例
const wait = function(val) { // 定义一个 promise 对象 const promise = new Promise((resolve, reject) => { // 将之前的异步操作,包括到这个 new Promise 函数之内 const task = function() { if (val) { console.log('执行完成'); resolve(true) } else { console.log('执行失败'); reject(false) } // callback 中去执行 resolve 或者 reject } setTimeout(task, 2000) }) // 返回 promise 对象 return promise}const w = wait (1);var a = 0;w.then((val) => { console.log('ok 1' + val); a = 231; console.log(a); return w;}, (val) => { console.log('err 1' + val)}).then((val) => { console.log('ok 2' + val); var b = a + 2; console.log(b)}, (val) => { console.log('err 2' + val)})复制代码
async :异步
依次读取两个文件:
var asyncReadFile = async function () {var f1 = await readFile('/etc/fstab');var f2 = await readFile('/etc/shells');console.log(f1.toString());console.log(f2.toString());};//注意 封装的readFile ()方法要返回promise对象async function getStockPriceByName(name) {var symbol = await getStockSymbol(name);var stockPrice = await getStockPrice(symbol);return stockPrice;}getStockPriceByName('goog').then(function (result) {console.log(result);});复制代码
使用注意点:
第一点,前面已经说过,await命令后面的Promise对象,运行结果可能是rejected,所以最好把await命令放在try...catch代码块中。
async function myFunction() {try {await somethingThatReturnsAPromise();} catch (err) {console.log(err);}}// 另一种写法 (推荐)async function myFunction() {await somethingThatReturnsAPromise().catch(function(err) {console.log(err);});}复制代码
因为以下所有的代码都会用到Promise,因此干脆在所有介绍之前,先封装一个Promise,封装一次,为下面多次应用。
const fs = require('fs')const path = require('path') // 后面获取文件路径时候会用到const readFilePromise = function (fileName) { return new Promise((resolve, reject) => { fs.readFile(fileName, (err, data) => { if (err) { reject(err) // 注意,这里执行 reject 是传递了参数,后面会有地方接收到这个参数 } else { resolve(data.toString()) // 注意,这里执行 resolve 时传递了参数,后面会有地方接收到这个参数 } }) })}复制代码
那么前面步骤return的值会被当做参数传递给后面步骤的函数,如下面代码中的a就接收到了return JSON.parse(data).a的值
const fullFileName = path.resolve(__dirname, '../data/data2.json')const result = readFilePromise(fullFileName)result.then(data => { // 第一步操作 console.log(data) return JSON.parse(data).a // 这里将 a 属性的值 return}).then(a => { // 第二步操作 console.log(a) // 这里可以获取上一步 return 过来的值})复制代码
我们知道then会接收两个参数(函数),第一个参数会在执行resolve之后触发(还能传递参数),第二个参数会在执行reject之后触发(其实也可以传递参数,和resolve传递参数一样),但是上面的例子中,我们没有用到then的第二个参数。这是为何呢 ———— 因为不建议这么用。
对于Promise中的异常处理,我们建议用catch方法,而不是then的第二个参数。请看下面的代码,以及注释。
const fullFileName = path.resolve(__dirname, '../data/data2.json')const result = readFilePromise(fullFileName)result.then(data => { console.log(data) return JSON.parse(data).a;}).then(a => { console.log(a)}).catch(err => { console.log(err.stack) // 这里的 catch 就能捕获 readFilePromise 中触发的 reject ,而且能接收 reject 传递的参数})复制代码
读取两个文件data1.json和data2.json,现在我需要一起读取这两个文件,等待它们全部都被读取完,再做下一步的操作。此时需要用到Promise.all。(以前记得做个打印报表的功能。当时报表数据差不多几万条。所以想到了分页打印。比如分5页,每页200条。那么打印的时候肯定要按顺序打印。即1-200,201-300以此打印。那么就写了个方法,循环遍历整个数据,每200条放到一个方法中,结果把5个方法再push到一个数组中。记得当时用的是$q 里面的all()方法来执行的。)
// Promise.all 接收一个包含多个 promise 对象的数组Promise.all([result1, result2]).then(datas => { // 接收到的 datas 是一个数组,result1, result2 依次执行,返回包含了多个 promise的内容 console.log(datas[0]) console.log(datas[1])}) var funcA = function(){ console.log("funcA"); return "hello,funA"; } var funcB = function(){ console.log("funcB"); return "hello,funB"; } var a = [funcA ,funcB]; Promise.all([funcA , funcB]).then(datas => { // Promise.all(a).then() // 接收到的 datas 是一个数组,依次包含了多个 promise 返回的内容 console.log(datas[0]) console.log(datas[1])})复制代码
读取两个文件data1.json和data2.json,现在我需要一起读取这两个文件,但是只要有一个已经读取了,就可以进行下一步的操作。此时需要用到Promise.race
// Promise.race 接收一个包含多个 promise 对象的数组Promise.race([result1, result2]).then(data => {// data 即最先执行完成的 promise 的返回值console.log(data)})复制代码
栗子:
var uploadQuestion = function(questions) {var promises = [];angular.forEach(questions, function(question) {var promise = $http({ //url: 'upload/question',method: 'POST',data: question});promises.push(promise);});return $q.all(promises);}复制代码
$q:异步
var iWantResolve = true;function es6promise() { return $q(function(resolve, reject) { $timeout(function() { if (iWantResolve) { resolve("es6promise resolved"); } else { reject("es6promise reject"); } }, 1000) })}es6promise() .then(function(data) { console.log(data); }) .catch(function(err) { console.log(err); });// if(iWantResolve == true) output: es6promise resolved// if(iWantResolve = false) output: es6promise reject复制代码
function commonJsPromise() { var deferred = $q.defer(); $timeout(function() { //可以没有 deferred.notify("commonJS notify"); if (iWantResolve) { deferred.resolve("commonJS resolved"); } else { deferred.reject("commonJS reject"); } }, 500); return deferred.promise;}commonJsPromise() .then(function /** success callback**/ (data) { console.log(data); }, function /** error callback **/ (err) { console.log(err); }, function /** progress callback **/ (update) { console.log(update); });// if(iWantResolve == true) output: commonJS notify commonJS resolved// if(iWantResolve = false) output: commonJS notify commonJS reject复制代码
$q.all([es6promise(), commonJsPromise()]) .then(function (dataArr) { console.log("$q.all: ", dataArr); }, function (err) { console.log("$q.all: ", err) }, function /** unnecessary **/ (update) { console.log("$q.all", update); });// if(iWantResolve == true) output: $q.all: ["es6promise resolved", "commonJS resolved"]// if(iWantResolve = false) output: $q.all: es6promise reject复制代码
大家都是到 jquery v1.5 之后$.ajax()返回的是一个deferred对象,而这个deferred对象和我们现在正在学习的Promise对象已经很接近了,但是还不一样。那么 ———— deferred对象能否转换成 ES6 的Promise对象来使用??
答案是能!需要使用Promise.resolve来实现这一功能,请看以下代码:
// 在浏览器环境下运行,而非node 环境
const jsPromise =Promise.resolve($.ajax('/whatever.json'))jsPromise.then(data => {// ...})//ajax 异步执行方法复制代码
其实,在我们的日常开发中,这种将thenable转换为Promise的需求并不多。真正需要的是,将一些异步操作函数(如fs.readFile)转换为Promise(就像文章一开始readFilePromise做的那样)而且then必须返回一个promise,同一个 promise 的then可以调用多次(链式)” ——— 这两句话说明了一个意思 ——— then肯定要再返回一个promise,要不然then后面怎么能再链式的跟一个then呢?
const w9991 = wait(1)w9991.then((val) => {console.log('ok 1'+val);// ok 1true ok 2true //2不是undefinedreturn w9991;}).then((val) => {console.log('ok 2'+val); })复制代码
eg:
function readFilePromise() { return new Promise((resolve, reject) => { resolve(setTimeout(() => { console.log(1111); })); })};const readFileAsync = async function() { const f1 = await readFilePromise(); const f2 = await readFilePromise(); return 'done' // 先忽略,后面会讲到 } // 执行const result = readFileAsync() //1111 1111result.then(data => { console.log(data) // done})复制代码
使用async-await的不同和好处
第一,await后面不能再跟thunk函数,而必须跟一个Promise对象(因此,Promise才是异步的终极解决方案和未来)。跟其他类型的数据也OK,但是会直接同步执行,而不是异步。
第二,执行const result = readFileAsync()返回的是个Promise对象,而且上面代码中的return 'done'会直接被下面的then函数接收到
result.then(data => {console.log(data) // done})复制代码
第三,从代码的易读性来将,async-await更加易读简介,也更加符合代码的语意。而且还不用引用第三方库,也无需学习Generator那一堆东西,使用成本非常低。
总结:
异步操作 : promise \generator yield \async-await\$q
17、正则
这个我只会简单的就不在此卖弄了。。。呵呵哒
18、window 对象(html5 api)
下期见。。。
19、模块化封装方法(exports、 module exports 、export default)
下期见。。。
总结: 文章穿插有点大 .都是笔者随心写的。第一次写,如有错误请指正。请多多关照!!呵呵哒.
备注:文章有些是以前的学习笔记,直接拷贝上来的。侵删!