ES6-语法基础

2022-11-15 13:24:19 浏览数 (2)

1 ES6 的兼容性和新特性

1.1 兼容性

IE10 、Chrome、FireFox、移动端等新一代浏览器。

1.2 对旧版本的浏览器支持方式

(1)方式一:在线转换(使用 babel 转译库) 

代码语言:javascript复制
<script src="browser.js" ></script>
<script type="text/babel"> ... </script>

(2)方式二:提前编译

1.3 ES6 的新特性

(1)变量定义的改进;

(2)箭头函数;

(3)数组 和 字符串 的改进;

(4)面向对象;

(5)Promise;

(6)generator;

(8)模块化。

2 ES6 中的变量

2.1 var定义变量的问题

(1)可以重复声明;(2)无法限制修改(无常量);(3)没有块级作用域。

代码语言:javascript复制
if(true){
    var a = 12;
}
alert(a);   //正常运行,依然可以使用

2.2 let :不能重复声明的块级变量

不能重复声明:

代码语言:javascript复制
let a=10; let a=15; //a变量重复定义,SyntaxError
alert(a);

块级作用域:

代码语言:javascript复制
if(true){
    let a = 12;
}
alert(a);   //超出作用域,ReferenceError

块级作用域的重要性:

代码语言:javascript复制
window.onload = function(){
    var buttons = document.getElementsByTagName("button");
    for(var i=0; i<buttons.length; i  ){                    //使用var,每个按钮点击都显示3;改用let,则正确显示了按钮格各自下标
        buttons[i].onclick = function(){
            alert(i);
        };
    }
};

2.3 const :不能重复声明的块级常量

3 函数

3.1 箭头函数(Lambda表达式)

箭头函数是把函数简写成一个表达式;如果只有一个参数,()可以省略;如果只有一个行,{ }可以省略,return 可以省略。

(参数1,...) => { 函数体; }

代码语言:javascript复制
let arr = [5,3,4,7,6,2];
arr.sort( (n1,n2)=>n2-n1 );

3.2 默认参数

代码语言:javascript复制
function show(a, b=5, c=10){
    alert([a,b,c]);
}
show(1,2)

4 展开运算符

语法:...数组变量

(1)参数的收集(不定参数)

代码语言:javascript复制
function showOthers(a,b,...others){
  alert(others);
}
showOthers(1,2,3,4,5);  //显示3,4,5

(2)数组的展开

代码语言:javascript复制
function showSeperate(a,b,c){
    alert(a); alert(b); alert(c);
}
showSeperate(...args);

(3)多个数组展开

代码语言:javascript复制
let arr1 = [3,2,1]; let arr2 = [4,5,6];
let arr3 = [...arr1, ...arr2];

5 解构赋值

5.1 解构赋值要点:(1)左右两边结构相同;(2)右边必须是对象(数组)(3)声明和赋值不能分开。

5.2 具体使用

(1)数组的解构赋值

代码语言:javascript复制
let arr=[1,2,3];
[x,y,z] = arr;          //x=arr[0]; y=arr[1]; z=arr[2];

(2)对象的解构赋值

代码语言:javascript复制
let point = {x:3,y:-5};
let {x,y}=point;        //变量需要与对象属性同名才能赋值

(3)复合

代码语言:javascript复制
let [obj,arr,num,str]=[{x:10,y:20},[1,2,3],101,'hi'];
console.log(obj,arr,num,str);
let [{x,y},[n1,n2,n3],num,str]=[{x:10,y:20},[1,2,3],101,'hi'];
console.log(x,y,n1,n2,n3,num,str)

6 数组的增强

(1)map         映射函数(1对1变换)

代码语言:javascript复制
let arr=[95,72,55,100,45,33];
let result = arr.map(x=>x>=60?'Pass':'Fail');       //["Pass", "Pass", "Fail", "Pass", "Fail", "Fail"]

(2)reduce     汇总函数

代码语言:javascript复制
let arr=[95,72,55,100,45,33];
let sum = arr.reduce((tmp, item, index)=>{
    console.log(tmp, item, index);
    return tmp item;
});

值得注意的是当数组为空时,reduce可能会出错,需要额外加入一个初始值(可以是0也可以根据需要设定)。

代码语言:javascript复制
let arr=[];
var result = arr.reduce((x,y)=>x y);        //错误,TypeError,
var result = arr.reduce((x,y)=>x y, 0);     //正确,返回初始值 0

 (3)filter          过滤

代码语言:javascript复制
let arr=[95,72,55,100,45,33];
let result = arr.filter(x=>x>=60);

(4)forEach    迭代

代码语言:javascript复制
arr.forEach(x=>console.log(x))

7 模板字符串

ES6中可以使用反引号(`)定义模板字符串。模板字符串可以在字符串中换行;也可以把变量放入模板字符串的占位符中。

代码语言:javascript复制
let title = "Hello ES6";
let tmpl = `<div>
    <h1>${title}</h1>
</div>`;

8 面向对象

8.1 传统的对象化

(1)对象的定义

代码语言:javascript复制
function User(name,pass){
    this.name = name;
    this.pass = pass;
}
User.prototype.sayHi = function(){
    alert("Hi, I'm " this.name);
}
var user = new User("zhang3","123");
user.sayHi();

(2)对象继承

代码语言:javascript复制
function VipUser(name, pass, level){
    User.call(this, name, pass);
    this.level = level;
}
VipUser.prototype = new User();
VipUser.prototype.construtctor = VipUser;
VipUser.prototype.showLevel = function(){
    alert("My Level is: " this.level);
}
var vip = new VipUser("li4","123",5);
vip.sayHi();
vip.showLevel();

8.2 ES6中的面向对象

(1)类的定义

使用 class 关键字定义类;新增 constructor 声明构造方法;可以在 class 中直接定义方法“方法名(参数列表) { ...方法体... }”

代码语言:javascript复制
class User{
    constructor(name, pass){
        this.name = name;
        this.pass = pass;
    }
    sayHi(){
        alert("Hi, I'm " this.name);
    }
}

(2)类的继承

代码语言:javascript复制
class VipUser extends User{
    constructor(name, pass, level){
        super(name, pass);
        this.level = level;
    }
    showLevel(){
        alert("My Level is: " this.level);
    }
}
var vip = new VipUser("li4","123",5);
vip.sayHi();
vip.showLevel();

9 JSON语法改进

9.1 ES5 的 JSON 对象

(1)把字符串解释为JSON对象

代码语言:javascript复制
var line = '{"name":"zhang3","age":30}';
var obj = JSON.parse(line);

注意点:JSON字符串中的属性名必须使用引号声明:"属性名";JSON字符串中的字符串值只能使用双引号 "。

(2)把JSON对象序列化为字符串

代码语言:javascript复制
JSON.stringify(obj)

9.2 JSON的简写

(1)JSON对象的属性名和属性值(变量)同名时,变量值可以省略。

代码语言:javascript复制
var x=10;y=20;
var point = {x, y};   // {x: 10, y: 20}

(2)JSON对象的方法声明可以简写

代码语言:javascript复制
var point = {
    x, y,
    display(){ console.log(x, y); }     //等同于:display:function(){console.log(x,y);}
};

10 Promise 对象与异步调用

在JavaScript的世界中,所有代码都是单线程执行的由于这个“缺陷”,JavaScript的所有需要等待的操作(网络操作),都必须“异步执行”。“异步编程”通过“回调函数”实现,一个在“同步编程”中一段连续的调用,在“异步”中很可能会陷入“回调地狱”(Callback Hell)。

10.1 传统的AJAX回调

(1)AJAX回调

代码语言:javascript复制
function getUserInfo(){
        $.ajax({
            url:"data/user.json", 
            dataType:"json",
            success: function(user){ console.log(user); },
            error: function(err){ console.log(err); }
        });
    }
    getUserInfo();

(2)回调中的回调(Callback Hell)

代码语言:javascript复制
function getProductsOfUser(){
        $.ajax({
            url:"data/user.json", 
            dataType:"json",
            success: function(user){
                $.ajax({
                    url:"data/" user.username ".json",
                    dataType:"json",
                    success: function(products){
                        console.log(products);
                    },
                    error:function(err){ console.log(err); }
                });
            },
            error: function(err){ console.log(err); }
        });
    }
    getProductsOfUser();

10.2 使用 fetch 实现 Promise 异步调用。

实际中,支持 ES6 的浏览器,都可以使用 fetch 对象实现基于 Promise 的异步请求,无需使用 jQuery 实现异步调用。

上述示例可以使用 fetch 简单实现。

代码语言:javascript复制
fetch("data/user.json")
    .then(resp=>resp.json())
    .then(user=>fetch("data/" user.username ".json"))
    .then(resp=>resp.json())
    .then(products=>console.log(products))
    .catch(err=>console.log('请求失败'));

10.3 什么是 Promise 对象

Promise对象的出现,用链式调用的形式替代了嵌套回调,解决“回调地狱”问题。

(1) 一个简单的 Promise 示例

代码语言:javascript复制
//创建异步执行方法 async(resolve, reject),提供resolve(成功)和reject(失败)两个函数作为参数
function test(resolve, reject) {
    var timeOut = Math.random() * 2;
    console.log('设置超时时间为: '   timeOut   ' 秒.');
    setTimeout(function () {
        if (timeOut < 1) {
            console.log('调用 resolve()...');
            resolve('200 OK');
        }
        else {
            console.log('调用 reject()...');
            reject('超时 '   timeOut   ' 秒.');
        }
    }, timeOut * 1000);
};
//调用Promise,并实现 resolve(then)和reject(cache)
new Promise(test).then(function(result){
    console.log("成功:" result);
}).catch(function(reason){
    console.log("失败:" reason);
});

Promise对象的结构如下图所示:

(2)Promise 封装异步处理

代码语言:javascript复制
//获取用户信息
function getUser(){
    return new Promise(function(resolve,reject){
        $.ajax({
            url:"data/user.json", 
            dataType:"json",
            success: resolve,
            error: reject
        });
    })
}
getUser()
    .then(function(user){ console.log(user); })
    .catch(function(err){ console.log("加载失败",err); });

(3)Promise的串行调用

多个Promise对象可以使用 then方法实现串行化调用。

代码语言:javascript复制
//乘法
function multiply(input) {
    return new Promise(function (resolve, reject) {
        console.log('计算 '   input   ' x '   input   '...');
        setTimeout(resolve, 500, input * input);
    });
}
//加法
function add(input) {
    return new Promise(function (resolve, reject) {
        console.log('计算 '   input   '   '   input   '...');
        setTimeout(resolve, 500, input   input);
    });
}
//创建Promise,初始化Resolve
var p = new Promise(function (resolve, reject) {
    console.log('启动 new Promise...');
    resolve(123);
});
//串行调用多个Promise对象,前面的函数执行结果会传入到后面的函数
p.then(multiply)
 .then(add)
 .then(multiply)
 .then(add)
 .then(function (result) {
    console.log(': '   result);
});

(4)使用 Promise 串行执行多次AJAX回调

上述的fetch方法,then回调中的参数是响应而不是json,为了使用更简便,我们可以利用Promise的特性加上jQuery,自己实现一个then回调是json的Promise异步请求函数fetchJOSN,并实现多此Promise的嵌套调用。

代码语言:javascript复制
function fetchJSON(url){
  return new Promise((resolve, reject)=>{
    $.ajax({
      url:url,
      dataType:"json",
      success: resolve,
      error: reject
    })
  });
};
fetchJSON("data/user.json")
  .then(user => fetchJSON("data/" user.username "1.json"))
  .then(products=>console.log(products))
  .catch(err => console.log('请求失败', err));

11 Generator

11.1 generator的定义

generator(生成器)是ES6标准引入的新的数据类型。一个generator看上去像一个函数,但可以执行并返回多次。

语法:function* 生成器名( 参数... ){ ...函数体... }

代码语言:javascript复制
function* show(){
    alert('x');
    yield;          //退让
    alert('y');
}
let gen = show();
gen.next();         //显示x
gen.next();         //显示y

11.2 yield

(1)使用 yield 传参

代码语言:javascript复制
function* show(init){
    alert(init);
    let x = yield;
    alert(x); 
}
var gen = show(101);
gen.next();         //101
gen.next(202);      //202

(2)使用 yield 返回中间结果

代码语言:javascript复制
function* show(){
    alert('x');
    yield 101;          //返回
    alert('y');
}

执行效果如下图所示:

11.3 generator Promise

使用 generator 中的 yield 去调用一个 Promise 对象,就可以把异步调模仿成同步调用的形式来执行。

定义一个异步变同步的执行函数(syncRun.js):

代码语言:javascript复制
/* 把异步当做同步执行的函数,详见《你不知道的JavaScript-中卷》 4.4.1 */
function syncRun(gen){
    var args = [].slice.call(arguments, 1), it;
    //初始化生成器
    it = gen.apply(this, args);
    return Promise.resolve()
        .then(function handleNext(value){
            //对下一个yield出的值运行
            var next = it.next(value);         
            return (function handleResult(next){
                //生成器执行完了吗?
                if(next.done){
                    return next.value;  //执行完返回值
                }else{                  //否则继续执行
                    return Promise.resolve(next.value)
                        .then(
                            handleNext, 
                            function handleErr(err){
                                return Promise.resolve(it.throw(err))
                                    .then(handleResult);
                            }
                        );
                }
            })(next);
        });
}

把异步Promise以同步的形式执行。

代码语言:javascript复制
<script src="js/syncRun.js"></script>
<script>
    syncRun(function* (){
        let resp = yield fetch('data/user.json');
        let user = yield resp.json();
        resp = yield fetch('data/' user.username '.json');
        let products = yield resp.json();
        console.log(products);
    });

</script>

12 ES7 中的 async / await

ES7中添加了 async 与 await 关键字,可以进一步将Promise调用编写成类似同步的语法。

async函数是使用async关键字声明的函数。 async函数是AsyncFunction构造函数的实例, 并且其中允许使用await关键字。

async和await关键字让我们可以用一种更简洁的方式写出基于Promise的异步行为,而无需刻意地链式调用Promise。

例如有如下的Promise函数:

代码语言:javascript复制
var flag=false;   //用于控制Promise,模拟“成功”和“失败”
    //创建Promise函数
    function promiseFunc(){
      return new Promise((resolve, reject)=>{
        setTimeout(() => {
          if(flag)
            resolve("success");
          else
            reject("fail");   
        }, 2000);
      });
    }

下面时Promise的一般调用方式,我们需要编写成链式调用:

代码语言:javascript复制
 //链式调用Promise
    promiseFunc()
        .then(x=>console.log("链式调用Promise:",x))
        .catch(e=>console.log("链式处理异常:", e));

如果使用 async/await 方式调用,我们可以通过 async 方法返回值来获取 resovle(即then)回调中的参数,也可以通过 catch 来获得 reject(即catch)回调中得错误信息。

代码语言:javascript复制
 //在使用async函数中使用await调用Promise
    async function asyncFunc(){
      try{
        var x = await promiseFunc();
        console.log("await调用Promise:", x);
      }catch(e){            //异常处理可选
        console.log("await处理异常:", e);
      }
    }
    asyncFunc();

async函数还可以被作为表达式来定义,例如上述调用可以简化为以下得自执行函数:

代码语言:javascript复制
 //用自执行函数来直接await调用
    (async ()=>{
      try{
        var x = await promiseFunc();
        console.log("await调用Promise:", x);
      }catch(e){
        console.log("await处理异常:", e);
      }
    })()

0 人点赞