牛掰的ES6

牛掰的ES6(持续更新中…)

ES6简介:
  ECMAScript 6.0(以下简称ES6)是JavaScript语言的下一代标准,已经在2015年6月正式发布了。所以又称ECMAScript 2015。它的目标,是使得JavaScript语言可以用来编写复杂的大型应用程序,成为企业级开发语言。
  ECMAScript和JavaScript的关系是,前者是后者的规格,后者是前者的一种实现(另外的ECMAScript方言还有Jscript和ActionScript)。日常场合,这两个词是可以互换的。、在我们正式讲解ES6语法之前,我们得先了解下Babel。
  Babel是一个广泛使用的ES6转码器,可以将ES6代码转为ES5代码,从而在现有环境执行。大家可以选择自己习惯的工具来使用使用Babel,具体过程可直接在Babel官网查看。

文章目录

  • 牛掰的ES6(持续更新中...)
    • let和const命令
    • Promise
      • Promise介绍
      • Promise详解
      • then方法
      • 关于catch方法
      • Promise对象的两个特点
      • promise并发控制
        • promise.all
        • Promise.race的使用
    • Es6中字符串的一些新方法(6/7/8):
      • 模版字符串
        • repeat()
        • padStart(),padEnd()

let和const命令

1.作用域

​   被let和const命令声明的变量,只在let命令所在的代码块内生效,代码块外无法访问;

  ​ ES6 明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。

2.变量提升

​   与var不同,let和const声明的变量,不会发生“变量提升”现象,即变量不能在声明之前使用,一旦使用就会报错。

3.暂时性死区

​   在代码块内,使用let和const命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。

4.重复声明

​ 被let和const声明的变量不可重复声明。

  在ES6之前,JavaScript只有全局作用域和函数作用域,let命令实际上增加了块级作用域。块级作用域的应用场景:

​ 1.在函数作用域内声明变量

​ 2.在for循环中声明循环变量const声明一个只读的常量。一旦声明,常量的值就不能改变。

注意:const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。

Promise

  这可能是前端程序员处理异步最长用,用的最多的吧。哈哈哈。。。
  背景:在Javascript的世界里,所有代码都是单线程执行的。由于这个“缺陷”,导致JavaScript的所有网络操作,浏览器事件,都必须是异步执行。异步执行可以用回调函数实现,但是如果代码中异步代码比较多,也就意味着需要写很多回调函数,这样的代码难以读懂,维护困难,而且不利于复用。
我们希望不用写太多回调,而是也可以像同步代码一样链式执行,而Promise就是为了这种情况而生的。暂且不谈await、async。

Promise介绍

  Promise本身并不能实现任何业务,我们之所以要使用Promise只是为了不写回调,为了把本来异步的代码写成同步的形式,我们先来看一个简单的Promise处理异步的例子:承诺一秒之后生成的随机数大于0.5

const pro = new Promise((resolve, reject) => {
     
	setTimeout(() => {
     
		const num = Math.random()
		if (num > 0.5) resolve(num)
		else reject(num)
	}, 1000)
})
pro.then((n) => {
     
	console.log(n + '大于0.5,承诺兑现')
}).catch((n) => {
     
	console.log(n + '不大于0.5,承诺失信')
})

  变量pro是一个Promise对象,它负责执行参数里的函数,函数带有 resolve 和 reject 两个参数,resolve 和 reject 函数被调用时,分别将promise的状态改为fulfilled(完成)或rejected(失败)。
  Promise内部只负责判断和修改状态,并不需要执行具体的逻辑,承诺兑现的逻辑在then里执行,承诺失信的逻辑在catch里执行
  先来看个采用Promise后ajax的写法:

getData(method, url){
     
  var promise = new Promise(function(resolve, reject){
     
    var xmlHttp = new XMLHttpRequest();
    xmlHttp.open(method, url);
    xmlHttp.send();
    xmlHttp.onload = function () {
     
      if (this.status == 200 ) {
     
        resolve(this.response);
      } else {
     
        reject(this.statusText);
      }
    };
    xmlHttp.onerror = function () {
     
      reject(this.statusText);
    };
  })
  return promise;
}
getData('get','www.xxx.com').then(successFun, failFun)

Promise详解

ES6规定,Promise对象是一个构造函数,用来生成Promise实例。Promise 实例生成以后,可以用then 方法分别指定成功状态和失败状态的回调函数。
先提前准备几个后端接口

var express = require("express");
var app = express();

//设置跨域访问(设置在所有的请求前面即可)
app.all("*", function (req, res, next) {
     
  //设置允许跨域的域名,*代表允许任意域名跨域
  res.header("Access-Control-Allow-Origin", "*");
  //允许的header类型
  res.header("Access-Control-Allow-Headers", "content-type");
  //跨域允许的请求方式 
  res.header("Access-Control-Allow-Methods", "DELETE,PUT,POST,GET,OPTIONS");
  if (req.method == 'OPTIONS')
    res.sendStatus(200); //让options尝试请求快速结束
  else
    next();
});

// 第一个接口
app.get("/one", function (req, res) {
     
  res.send({
     
    state: true,
    des: "第一个接口请求成功,允许请求第二个接口"
  })
})
// 第二个接口
app.get("/two", function (req, res) {
     
  res.send({
     
    state: true,
    des: "第二个接口请求成功,允许请求第三个接口"
  })
})
// 第三个接口
app.get("/three", function (req, res) {
     
  res.send({
     
    state: true,
    des: "第三个接口请求成功!"
  })
})
app.listen(8081, function () {
     
  console.log("应用实例,访问地址为 http://127.0.0.1:8081");
});
            //这里是对位传参,只要参数名可以随意取,第一个参数可以理解为成功后的回调,第二个参数可以理解为失败后的回调

            const p = new Promise(function(resolve,reject){
      
            //发起异步操作,ajax请求
            ......
            if(/*异步操作成功*/){
     
                resolve(value); //在异步操作成功时调用,返回异步操作结果; 
            }
            else{
     
                reject(error); //在异步操作失败时调用,返回异步操作结果; 
            }
            });

            Var p1=p.then(function(data){
     
                console.info(data);
                //发起第二次请求
                //返回请求结果
            }
            );

then方法

  then方法可以接受两个回调函数作为参数。第一个回调函数是Promise 对象的状态变为resolved时调用,第二个回调函数是Promise 对象的状态变为rejected时调用。其中,第二个函数是可选的,不一定要提供。这两个函数都接受Promise 对象传出的值作为参数。

            var p1 = new Promise(function (reslove, reject) {
     
                $.getJSON(
                    "http://10.1.0.39:8081/check?key=123456",
                    function (data) {
     
                        if (data.mes != "正确") reject(data);
                        else reslove(data);
                    }
                );
            });
            var p2 = p1.then(
                // 成功的执行函数
                function (data) {
     
                    console.log("成功", "数据为:", data);
                },
                // 失败的执行函数
                function (data) {
     
                    console.log("失败", "数据为:", data);
                }
            );

关于catch方法

  正常情况then方法会接受两个参数,分别表示成功的处理函数和失败的处理函数。
但是很多时候我们可能含有多个then方法,这时如果要每个then里面都写上失败处理函数就太麻烦了,这时我们就可以使用catch方法。

我们在最末尾加上catch方法,那么他就可以捕获前面任何地方产生的错误,如下:
牛掰的ES6_第1张图片
注意:
一旦在catch前的某个then方法中写了第二个参数用于捕获错误,那么当前错误就会到此停止,后面就是正确的流程了。
如果在后面的流程中没产生其他错误,那么catch方法也不会再执行,如果出错了,那么catch仍然会继续执行。

Promise对象的两个特点

(1)对象的状态不受外界影响。
Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。
Promise 对象的状态改变,只有两种可能:从进行中变为已成功和从进行中变为已失败。只要这两种情况发生,状态就不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对 Promise 对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供统一的接口,使得控制异步操作更加容易。
Promise也有一些缺点。首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。第三,当处于进行中状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

promise并发控制

all / race

promise.all

  all和race两个函数都是并发执行promise的方法,他们的返回值也是promise,all会等所有的promise都决议之后决议,而race是只要有一个决议就会决议。

Promise.all([promise1, promise2, promise3]).then(function(values) {
     
  console.log(values);
});
//注意:如果参数为空,all方法会立刻决议,而race方法会挂住

先来看个列子:

// 假设后端有三个接口,
// 第一个接口验证口令是否正确,
// 如果口令正确就发起第二次请求获取当前用户名
// 如果第二个接口成功获取到了用户名了,就发起第三次请求:通过用户名获取用户的vip等级

// http://10.1.0.39:8081/check?key=123456
// http://10.1.0.39:8081/user
// http://10.1.0.39:8081/leave?username=张三

var p1 = new Promise(function (reslove, reject) {
     
$.getJSON('http://10.1.0.39:8081/check?key=123456', function (data) {
     
if (data.mes == '正确') {
     
reslove(data)
}else {
     
reject(data)
}
})
})

var p2 = p1.then(function (preData) {
     
return new Promise(function (resolve, reject) {
     
$.getJSON('http://10.1.0.39:8081/user', function (data) {
     
if (data.username == '张三') {
     
resolve(data)
}else {
     
reject(data)
}
})
})
})

var p3 = p2.then(function (preData) {
     
$.getJSON('http://10.1.0.39:8081/leave?username=张三', function (data) {
     
console.log(data)
})
})

是不是觉得不优雅,在追求优雅的道路上永无止境 !(ovo)这时候promise.all就派上用场了。

let p1 = new Promise((resolve, reject) => {
     
  resolve('成功了')
})

let p2 = new Promise((resolve, reject) => {
     
  resolve('success')
})

let p3 = Promse.reject('失败')

Promise.all([p1, p2]).then((result) => {
     
  console.log(result)               //['成功了', 'success']
}).catch((error) => {
     
  console.log(error)
})

Promise.all([p1,p3,p2]).then((result) => {
     
  console.log(result)
}).catch((error) => {
     
  console.log(error)      // 失败了,打出 '失败'
})

你学费了吗。。。。。。
  Promse.all在处理多个异步处理时非常有用,比如说一个页面上需要等两个或多个ajax的数据回来以后才正常显示,在此之前只显示loading图标。
  需要特别注意的是,Promise.all获得的成功结果的数组里面的数据顺序和Promise.all接收到的数组顺序是一致的,即p1的结果在前,即便p1的结果获取的比p2要晚。这带来了一个绝大的好处:在前端开发请求数据的过程中,偶尔会遇到发送多个请求并根据请求顺序获取和使用数据的场景,使用Promise.all毫无疑问可以解决这个问题。

面试题:封装一个promise.all方法(重点)

Promise.prototype.all = function(promises) {
     
  let results = [];
  let promiseCount = 0;
  let promisesLength = promises.length;
  return new Promise(function(resolve, reject) {
     
    for (let val of promises) {
     
      Promise.resolve(val).then(function(res) {
     
        promiseCount++;
        // results.push(res);
        results[i] = res;
        // 当所有函数都正确执行了,resolve输出所有返回结果。
        if (promiseCount === promisesLength) {
     
          return resolve(results);
        }
      }, function(err) {
     
        return reject(err);
      });
    }
  });
};

Promise.race的使用

顾名思义,Promse.race就是赛跑的意思,意思就是说,Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。

let p1 = new Promise((resolve, reject) => {
     
  setTimeout(() => {
     
    resolve('success')
  },1000)
})

let p2 = new Promise((resolve, reject) => {
     
  setTimeout(() => {
     
    reject('failed')
  }, 500)
})

Promise.race([p1, p2]).then((result) => {
     
  console.log(result)
}).catch((error) => {
     
  console.log(error)  // 打开的是 'failed'
})

原理是挺简单的,但是在实际运用中还没有想到什么的使用场景会使用到.自己也还没用过!

Es6中字符串的一些新方法(6/7/8):

模版字符串

  1. 使用反引号表示模板字符串
  2. 将表达式嵌入字符串中进行拼接。用${}来界定。
  3. 允许直接定义多行字符串
    牛掰的ES6_第2张图片
    注意:这三个方法都支持第二个参数,表示从哪里开始检索。其中,includes()和startsWith()的默认值是0,表示检索范围是参数值检索到末尾,很简单不多说。endsWith()很特殊,它第二个参数的默认值是字符串总长度值,表示检索范围是从开头检索到这个值。

repeat()

表示重复多少次。如果参数是正小数,会取整。如果参数是负数,会报错。如果参数是0,会得到空串。如果参数是字符串、布尔型或其他类型,会先换算成整数。

padStart(),padEnd()

这两个是ES8(也就是2017)新增方法,注意打开实验性JavaScript。

用于在开头补全字符和在末尾补全字符,padStart和padEnd一共接受两个参数,第一个参数用来指定字符串的最小长度,第二个参数是用来补全的字符串。

如果原字符串的长度,等于或大于指定的最小长度,则返回原字符串。

有一个问题是,如果用来补全的字符串与原字符串,两者的长度之和超过了指定的最小长度,js会截去右边超出位数的补全字符串,而原字符串是不会碰的。即使是padEnd也是截去右边超出的位数。

'abc'.padStart(10, '0123456789')
// '0123456abc'
'abc'.padEnd(10, '0123456789')
// 'abc0123456'

如果没有缺省第二个参数,默认填充空格。
顶不住了,今天先这样,跑步睡觉了。你的点赞是我坚持的动力,爱你哦~~~

你可能感兴趣的:(es6,javascript)