JavaScript ES6相关的一些知识(/let、const/箭头函数/Promise/generate)

javascript/jquery

浏览数:396

2019-4-19

ES6是个啥

ECMAScript是国际通过的标准化脚本语言
JavaScript由ES,BOM,DOM组成
ES是JavaScript的语言规范,同时JavaScript是ES的实现和扩展
6就是JavaScript语言的下一代标准

关于ES6的一些知识

1.let、const

ES5中的作用域有:函数作用域,全局作用域
ES6新增了块级作用域。由{}包括(if和for语句也属于块级作用域)

{
    var a = 1;
    let b = 2;
    
}
console.log(a)//1
console.log(b)//undefined

let、const、var的区别
var:可以跨块级作用域访问,不能跨函数作用域访问
let:只能在块级作用域访问,不能跨函数使用
const:定义常量,必须初始化且不能修改,只能在块级作用域内使用
关于变量提升:var不论声明在何处都会莫默认提升到函数/全局最顶部,但是let和const不会进行变量提升

2.arrow function 箭头函数

箭头函数相当于匿名函数,简化了函数的定义
定义就用=> 一个箭头

箭头函数有两种格式:
第一种:只包含一个表达式

x=>x++

相当于

function(x)}{
    return x++;
}

第二种:包含多条语句:

//包含判断等
x=>{
    if(x>0){
        return x++;
    }
    else{
        x--;
    }
}
//多个参数
(x,y,z....)=>x+y+z+...+
//无参数
()=>1

//返回对象
x=>({obj:x})//注意符号,避免和函数体的{}冲突

使用箭头函数时,函数体内的this对象,就是定义时所在的对象

3.Promise

定义:Promise对象用于异步操作,它表示一个尚未完成且预计在未来完成的异步操作

关于同步&异步
JavaScript是基于事件驱动的单线程运行机制
(why: 浏览器中至少有三个线程:js引擎线程,gui渲染线程,浏览器事件触发线程
js操作dom,浏览器事件触发都会影响gui渲染效果,因此他们之间存在互斥的关系,使用多线程会带来非常复杂的同步问题(a线程在某个DOM节点添加内容。b线程删除了该节点)
同步:
即单线程模式,所有的任务都在主线程上执行,形成一个执行栈*,如函数调用后需要等待函数执行结束后才能进行下一个任务,如果某个任务执行时间过长(如死循环),容易造成线程阻塞,影响下面任务的正常进行
异步:
可以一起执行多个任务,函数调用后不会立刻就返回执行结果,异步任务会在当前脚本所有的同步任务执行结束后再执行。异步任务不进入主线程,而是进入任务队列,在某个任务可以执行时,等待主线程读取任务队列,随后该任务将进入主线程执行
异步任务的实现,最经典的就是setTimeout()/setInterval()
他们的内部运行机制完全一样,前者指定的代码只执行一次,后者为反复执行

setTimeout(function(){
    console.log("taskA,yibu");
},0)

console.log("taskB,tongbu");
//taskB,tongbu
//taskA,yibu

即使延时事件为0,但由于它属于异步任务,仍需要等待同步任务执行结束后再执行

综合看,整体的执行顺序为:先执行执行栈中的内容,执行完毕后,读取任务队列,寻找对应的异步任务,结束等待状态,进入执行栈执行,不断循环(Event Loop)
只要主线程空了,就会去读取任务队列

关于回调函数,callback()
回调函数即是会被主线程挂起的代码
异步任务必须指定回调函数,当主线程开始读取任务队列,执行异步任务的时候,执行的就是对应的回调函数

言归正传,继续理解Promise

promise的三种状态:

  1. pending:初始状态
  2. fulfilled:操作成功
  3. rejected:操作失败

Promise可以由1->2/1->3一旦状态变化,便会一直保持这个状态,不再改变。
当状态改变Promise.then绑定的函数就会被调用

构建Promise

var promise = new Promise(function(resolve,reject){
    if(/*操作成功*/)
        resolve(data);
    else
        reject(error);
});

异步操作成功调用resolve,将结果作为参数传递出去
异步操作失败调用reject,将报出的错误作为参数传递出去

Promise构建完成后,使用then方法指定resolve状态和reject状态的回调函数
promise.then(成功回调函数,失败的回调函数(非必要))
//这两个函数都接受promise传出的值作为参数

promise.then(function(data){do xxxx for success},function(error){do xxxx for failure});

Promise新建后就执行,then方法指定的回调函数会在当前脚本的所有同步任务执行结束后再执行

例子:

var promise = new Promise(function(resolve, reject) {
  console.log('before resolved');
  resolve();
  console.log('after resolved');
});

promise.then(function() {
  console.log('resolved');
});

console.log('outer');

//before resolved
//after resolved
//outer
//resolved

Promise的优势在于,可以在then方法中继续写Promise对象并返回,然后继续调用then来进行回调操作。能够简化层层回调的写法。
Promise的精髓在于,用维护状态、传递状态的方式使得回调函数能够及时调用,比传递callback要简单、灵活

Promise的其他方法

.catch()

用于指定发生错误时的回调函数,等同于reject部分
和reject的区别:
promise.then(onFulfilled,onRejected)在onFulfilled发生异常,在onRejected中捕获不到
promise.then(onFulfilled).catch(onRejected)能够捕获异常。也可以用then替换,只是写法不同。本质上没有区别

.all()

用于将多个Promise实例包装成一个新的Promise实例

var p = Promise.all([p1, p2, p3]);

p1p2p3都需为promise实例
当p1p2p3都为fulfilled时,p才会变为fulfilled
只要有一个变为rejected,p就会变成rejected

.race()

用于将多个Promise实例包装成一个新的Promise实例
与all()的区别类似于 AND 和 OR
p1p2p3有一个状态发生改变,p的状态就发生改变,并返回第一个改变状态的promsie返回值,传递给p

.resolve()

看作new Promise()的快捷方式
实例:

Promise.resolve('Success');

/*******等同于*******/
new Promise(function (resolve) {
    resolve('Success');
});

让对象立刻进入resolved状态

4.generate

可以将generate理解为一个能够多次返回的“函数”

function* foo(x){
    yield x++;
    yield x+2;
    yield x+3;
    return x*x;
}

function*定义,并且yield也可以返回数据

调用generate的方法:
不断的使用next()

var f = foo(0);
console.log(f.next());// 0 false
console.log(f.next());// 3 false
console.log(f.next());// 4 false
console.log(f.next());// 1 true

使用for of结构

for (var x of foo(0)) {
    console.log(x); // 依次输出0 3 4 (没有输出1原因不详)
}

每执行一次后就暂停,返回的值就是yield的返回值,每次返回一个值,直到done为true,这个generate对象已经全部执行完毕
generate更像一个能够记住执行状态的函数

实际上generate不算是一个函数,它的返回值不是变量也不是函数,而是一个可迭代的对象
该对象类似一个元素被定义好的数组,保存的是一种规则而不元素本身,不能够随机访问,遍历也只能够遍历一次,因为规则只保存了上次的状态

参考文档1:讲解JavaScript的线程运作

参考文档2:讲解Promise

参考文档3:关于generate