前端框架Vue自学之ES6基本语法(补充)

本博客目的:记录Vue学习的进度和心得(ES6基本语法)

内容:掌握Vue中常用的ES6基础语法。

正文:

ES6基本语法

一、let与var(闭包,块级作用域)

  1、事实上var的设计可以看成JavaScript语言设计上的错误,但是这种错误多半不能修复和移除,因为需要向后兼容。例如if/for的块级的影响(ES5中if、for没有作用域,只有函数有作用域),因而JS作者引入了let,我们可以将let看成更完美的var(let有块级作用域(作用域:在一定范围内是可用的),var通常是定义全局变量的)。

  2、先前for的块级影响,通常的解决方法是使用闭包(因为函数有自己的作用域,应用外面的变量,能正确解决传参的问题)。(闭包是指有权访问另一个函数作用域中的变量的函数,或者说,函数对象可以通过作用域关联起来,函数体内的变量都可以保存在函数作用域内,这在计算机科学文献中称为“闭包”,所有的javascirpt函数都是闭包)

  3、ES6中let具有块级作用域。ES5中var是没有块级作用域的。

二、const

  1、在JavaScript中,使用const修饰的标识符为常量。不可再次赋值,可以用来保证数据的安全性。

  2、建议:在ES6开发中,优先使用const,只有需要改变某一个标识符额时候才使用let。

  3、在使用const定义标识符时,必须进行赋值。

  4、常量的含义是向的对象不能修改,但是可以改变对象内部的属性。(相当于是在内存空间,const指定了一个固定的对象内存地址(指向对象),但是我们可以修改内部的数据)

三、对象字面量的增强写法

  1、属性的增强写法。相当于把变量名称作为key,对应的值作为value。

1 const name = 'abc';
2 const height = 1.80;
3 
4 const obj = {
5     name,
6     height,
7 };
8 console.log(obj);//{ name: 'abc', height: 1.8 } 

  2、函数的增强写法。

1 const obj = {
2     run(){
3 
4     },
5     done(){
6 
7     }
8 };

四、for循环

  1、普通的for循环。用具有块作用域的let控制循环变量。如for(let i = 0; i < item.length; i++){item[i]...}。

  2、for(let i in items){i.....} 。{}里面可以正确调用i的索引。

  3、for(let item of items){item}。{}里面可以直接遍历items,生成一个个item对象。

  4、reduce/filter/map。对于数组来说:(看代码例子)【超级好用!】

  filter函数的使用。filter中的回调函数有一个要求:必须返回一个布尔值,当返回true时,函数内部会自动将这次回调的参数加入到新的数组中,当返回false时,函数内部会过滤掉这个参数。

  map函数的使用。对数组的每个元素都进行处理,返回处理后的结果。

  reduce函数的使用。reduce是对数组中所有的内容进行汇总。可以传入两个参数,第一个参数是个函数,第二个参数是初始返回值。

  上述函数可以链式组合。(这就是函数式编程)(tips:编程范式分类:命令式编程/声明式编程;面向对象编程(第一公民:对象)/函数式编程(第一公民:函数)。例如vue、react框架就是声明式编程,JavaScript就是函数式编程。)

 1 const nums = [10, 20, 420, 50, 40,]
 2 let newNums = nums.filter(function(n){
 3     return n < 100;
 4 });
 5 console.log(newNums);//[ 10, 20, 50, 40 ]
 6 let new2Nums = newNums.map(function(n){
 7     return n*2;
 8 });
 9 console.log(new2Nums);//[ 20, 40, 100, 80 ]
10 let new3Nums = new2Nums.reduce(function(preValue, n) {
11     return preValue + n;
12 },0);
13 //一共遍历4次,第1次:preValue 0 n 20 返回20(0+20)
14 //第2次:preValue 20 n 40 返回 60;
15 //第3次:preValue 60 n 100 返回 160;
16 //第4次:preValue 160 n 80 返回 240;
17 console.log(new3Nums);//240
18 //上述函数可以链式组合
19 let finalResult = nums.filter(function(n){
20     return n < 100;
21 }).map(function(n){
22     return n*2;
23 }).reduce(function(preValue, n) {
24     return preValue + n;
25 }, 0);
26 console.log(finalResult);//240
27 //还可以结合ES6的箭头函数写法
28 let finalResult2 = nums.filter(n => n < 100).map(n => n * 2).reduce((pre, n) => pre + n,0)
29 console.log(finalResult2);//240

五、箭头函数的使用和this指向

  1、箭头函数

  箭头函数是ES6特有的一种函数的写法,其目的是简化写法。

 1 // 格式1:
 2 // const a = (参数列表) =>{
 3 //     // 函数体
 4 // }
 5 // 例子1: 两个参数
 6 const sum = (num1, num2) => {
 7     return num1 + num2
 8 }
 9 // 例子2:一个参数时,小括号可以省略
10 const power = num => {
11     return num * num
12 }//等价于 const power = num => num * num

  当函数体代码块只有一行代码时,还可以简写,把return省略。

 1 const sum2 = (num1, num2) => num1 + num2 

  2、箭头函数的this指向(可以参考这个博客:js的this指向问题

  ES5中,this总是指向调用的对象。  

  箭头函数中的this是向外层作用域中, 一层层查找this,直到有this的定义(父级作用域的this保持一致)。下例中,第一个this,setTimeout中的function可以理解为callback(回调函数),相当于在setTimeout调用一个外部定义的函数,而这个函数没有显式绑定对象,所以其this指向window对象。而第二个this,由于使用的是箭头函数,箭头函数的this会绑定父级作用域,所以虽然在setTimeout调用一个外部定义的函数,这个箭头函数的外层作用域是aaa函数,这个aaa函数作用域的this,就是指向这个obj。

 1 const obj = {
 2     aaa() {
 3         setTimeout(function () {
 4             console.log(this);//指向window对象
 5         })
 6         setTimeout(() => {
 7             console.log(this);//指向obj对象
 8         })
 9     }
10 }

  

六、Promise

  1、什么是promise及基本使用

  promise是异步(async)编程的一种解决方案。(ES6引入)

  同步(sync)的缺点就是可能会产生阻塞,例如,用户在往服务器请求一些数据,如果使用的是同步,那么用户只能等待请求完数据才能进行别的操作,即产生了阻塞,这样用户体验是非常不好的。

  处理异步事件的一种很常见的场景是网络请求。我们封装一个网络请求的函数,因为不能立即拿到结果,所以不能像简单的3+4=7一样将结果返回。所以往往我们会传入另外一个函数,在数据请求成功时,将数据通过传入的函数回调出去。如果只是一个简单的网络请求,那么这种方案不会给我们带来很大的麻烦。但是当网络请求非常复杂时,就会出现回调地狱(callback hell),回调中嵌套着回调

  所以使用promise可以解决这个问题。

  这里,我们用一个定时器(setTImeout)来模拟异步事件:假设下面的data是从网络上1秒后请求的数据,console.log就是我们的处理方式。

  前端框架Vue自学之ES6基本语法(补充)

   我们将它换成promise代码,即进行promise封装。

  前端框架Vue自学之ES6基本语法(补充)

   其中,Promise是一个类,里面以一个函数作为参数,这个函数本身又包含两个参数:resolve,reject。resolve,reject本身又是函数。然后异步操作放置在promise中,但是我们不希望所有异步操作(如果很多个的话)都集中写在里面(不然和没有封装一样了,还是会出现回调地狱),我们需要调用resolve函数,resolve函数匹配一个函数叫then,然后把异步操作的代码放置在此,resolve把一些数据会传给then。注意then可以返回的一个新建的promise对象,在这个对象可以封装着另一个异步操作(这样代码结构逻辑就很清晰了)。这就是链式编程

  异步请求成功了调用resolve,失败了调用reject。对应地,reject函数对应一个函数叫catch,捕获错误,reject函数把这些数据传给catch,并执行catch函数。

  当我们使用new Promise()时,new就会执行Promise类的构造函数(保存了一些状态信息;执行传入的函数),在执行传入的回调函数时,传入两个参数,resolve和reject。  

  2、Promise的三种状态和另外处理方式

  首先,当我们开发中有异步操作时,就可以给异步操作包装一个Promise。异步操作之后会有三种状态:

  pending:等待状态,比如正在进行网络请求,或者定时器没有到时间。

  fulfill:满足状态,当我们主动回调了resolve时,就处于该状态,并且会回调.then()。

  reject:拒绝状态,当我们主动回调了reject时,就处于该状态,并且会回调.catch()。

   我们也可以在then里面把错误的情况写在里面。即then里面可以使用两个函数,函数1对应resolve传入的数据做处理,函数2对应reject传入的数据做处理(相当于catch())。

  前端框架Vue自学之ES6基本语法(补充)(此时,执行的是consolo.log(err))

   3、Promise的链式调用

  我们在看Promise的流程图时,发现无论是then还是catch都可以返回一个Promise对象。所以,我们的代码其实是可以进行链式调用的。

  前端框架Vue自学之ES6基本语法(补充)

  这里我们直接通过Promise包装了一下新的数据,将Promise对象返回了:Promise.resovle():将数据包装成Promise对象,并且在内部回调resolve函数;Promise.reject():将数据包装成Promise对象,并且在内部回调reject函数。

  (进一步简化)

  前端框架Vue自学之ES6基本语法(补充)

  还可以进一步简化,then里面的return的对象会被promise封装的

  前端框架Vue自学之ES6基本语法(补充)

  但并不是每次都是异步请求成功的,所以当有reject时,后续的then是不执行的,但catch可以捕获错误。

  前端框架Vue自学之ES6基本语法(补充)

   其也有简写,即使用Promise.reject()。此外,也可以是 throw 'error'来代替return Promise.reject('error')来抛出异常,也是可以被catch()捕获的。

    4、Promise的all方法使用

  假设我们需求本身需要两个网络请求,请求一和请求二。如何判断两个请求结果都有了呢?使用Promise.all()。只有都完成了,才会执行这个promise的then函数。results(是个iterator)返回的是上述请求的结果(两个)。

  前端框架Vue自学之ES6基本语法(补充)

七、