正文:
- JavaScript简介JavaScript 和java 没个卵的关系。 ECMAScript就是对实现该标准规定的各个方面内容的语言的描述。JavaScript实现了ECMAScript。 所以es5 es6 es7 是ECMAScript5 6 7 的简写。
- JavaScript在当前五个主要浏览器( IE、 Firefox、 Chrome、 Safari和 Opera)中都得到了不同程度的支持。 所以才有了兼容性的问题。
- 但人类的脚步是向前的。 比如babel 编译器解决了这种差异。统一编译成es5!
- 推荐在javaScript 中使用 "use strict" 。
"use strict"; //在正常模式中,如果一个变量没有声明就赋值,默认是全局变量。 严格模式禁止这种用法,全局变量必须显式声明。
"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"可以节省函数执行的时间。 推荐语句以一个分号结尾。
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
var 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、 new Boolean()问个问题:[] === ''
[]== ''
结果是什么? why?
typeof 返回的是字符串,有六种可能:
"number"、"string"、"boolean"、"function"、"undefined"、"object": {[],{}}
其中 null类型
typeof null === "object"
so 判断变量是数组还是对象的时候 要过滤null。
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 Math
var 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 属性, 相当于告诉浏览器立即下载,但延迟执行。
<script type = "text/javascript" defer = "defer" src = "example1.js" >
</script> )
拓展:同样与 defer 类似,async 只适用于外部脚本文件, 并告诉浏览器立即下载文件。 但与 defer 不同的是, 标记为 async 的脚本并不保证按照指定它们的先后顺序执行。 例如:
<script type = "text/javascript" async src = "example1.js" >
< /script>
<script type = "text/javascript" async src = "example2.js" >
< /script>
在以上代码中, 第二个脚本文件可能会在第一个脚本文件之前执行。 因此, 确保两者之间互不依赖 非常重要。指定 async 属性的目的是不让页面等待两个脚本下载和执行, 从而异步加载页面其他内容。为此, 建议异步脚本不要在加载期间修改 DOM。 异步脚本一定会在页面的 load 事件前执行,但可能会在 DOMContentLoaded 事件触发之前或之 后执行。 支持异步脚本的浏览器有Firefox 3.6、 Safari5 和 Chrome5、 来个运算符吧
var a = 0;
a++;
++a;
老生常谈了var a = 0;
a + +1 输出什么?
//1 why?
'' + 1
1 + ''
'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(); // cool
fn.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
为什么不是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) //34
Math.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. max(x,y) //返回 x 和 y 中的最高值。
Math.min(x,y)// 返回x 和 y 中的最低值。
Math. pow(x,y) //返回 x 的 y 次幂。
Math. random()// 返回 0 ~ 1 之间的随机数。
Math. round(x) //把数四舍五入为最接近的整数。
Math.trunc(2.643) //2 截取小数点前面的数字
12、DateVar a = new Date();
本地全部时间格式:
toLocaleString(); // "2017/11/16 下午4:27:09"
a.toLocaleDateString() //"2017/11/16"
toLocaleTimeString() // "下午4:27:09"
getFullYear() //2017
getTime()
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)
})
}
es6 promise()
.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不是undefined
return 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 1111
result.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 对象 19、模块化封装方法(exports、 module exports 、export default)