IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> ES6新特性介绍 -> 正文阅读

[JavaScript知识库]ES6新特性介绍

1、ES6与JavaScript的关系

????????JavaScript 由 Brendan Eich 于 1995 年发明,并于 1997 年成为 ECMA 标准。

????????ECMAScript 是该语言的官方名称。

????????从 2015 年起,ECMAScript 按年命名(ECMAScript 2015)。

????????ES6 指的是 ECMAScript 的第六代版本 因发布时间为2015年 又可称为 ECMAScript 2015。

????????ECMAScript 主要版本:

????????浏览器支持情况:

?

2、变量声明const和let

???ES6 新增了 const 关键字用于声明常量, let 关键字声明变量。

????????const 声明的变量为常量,常量在声明时必须赋值,声明后不能被修改:

const?PI?=?3.14;
PI?=?3.1415;  //报错 Uncaught TypeError: Assignment to constant variable.

????????如果 const 声明的常量是一个对象,对象所包含的属性值是可以被修改的,但不能替换为一个新的对象即对象的引用地址不能修改:

const car = {color:'red'};
car.color = 'black';     //可以修改  111027110181937
car = {color:'black'};   //报错 Uncaught TypeError: Assignment to constant variable.

????????const 为块级作用域,即在所属的大括号范围内有效。超出范围程序将抛出错误:

{
    var i = 1;
 	 const j = 2;
}
console.log("i=" + i);   //输出 i=1
console.log("j=" + j);   //报错 Uncaught ReferenceError: j is not defined

????????与 const 一样, let 声明的变量也是块级作用域,即在所属的大括号范围内有效。超出范围程序将抛出错误:

{
    var i = 1;
 	 let j = 2;
}
console.log("i=" + i);   //输出 i=1
console.log("j=" + j);   //报错 Uncaught ReferenceError: j is not defined

????????区别于 var,let 关键词声明的变量不具备变量提升(hoisting)特性:

console.log("i=" + i);  //输出 i=undefined
var i = 1;
console.log("j=" + j);  //报错 VM320:3 Uncaught ReferenceError: j is not defined
let j = 2;

????????区别于 var,同一作用域内,let 变量不能重复声明:

var i = 1;
var i = 2;   //可以重复声明
let j = 3;
let j = 4;   //报错 VM287:4 Uncaught SyntaxError: Identifier 'j' has already been declared

????????var 的变量提升(hoisting)特性:

var?i?=?1;?????????????//?全局变量i
f();???????????????????//?f是函数,虽然定义在调用的后面,但是函数声明会提升到作用域的顶部。?
console.log(i);????????//?i?=?1,??当前为全局变量i
function?f()?{
??console.log(i);??????//?当前i是下一行的i的声明提升后的默认值undefined
??var?i?=?2;???????????//局部变量
??console.log(i);??????//?i?=?2
}

????????运行结果:

????????let 在 for 循环中的作用域:

for (var i = 0; i < 10; i++) {
   setTimeout(function () {
    console.log("i=" + i);
  }, 0);
}      // 输出 10次 i=10
for (let j = 0; j < 10; j++) {
   setTimeout(function () {
    console.log("j=" + j);
  }, 0);
}     // 循环输出 j=0 到 j=9

????????运行结果:

3、模板字符串

?模板字符串(template string)是传统的javascript字符串的加强版。用反引号 `` 标识。它可以当作普通字符串使用,也可以用来方便的处理多行字符串和在字符串中嵌入变量。

????????普通字符串。与传统javascript字符串使用一致:

?let?hello?=?`hello?world`;

????????字符串中如果需要使用反引号,则需要在前面添加反斜杠进行转义:

let hi = `\`hi\`, dude`;

????????处理多行字符串。使用传统字符串需要使用换行和缩进的时候使用 + 或者 concat() 进行拼接是一件复杂而痛苦的事情。而模板字符串允许在反引号范围内任意的换行和缩进,所有的换行和缩进格式都能得到保留,非常方便:

let?table?=?`
????????<table>
????????????<tr>
????????????????<td>cell</td>
????????????????<td>cell</td>
????????????</tr>
????????</table>
????????`;
console.log(table);

????????打印结果:

?????????在字符串中嵌入变量。传统字符串可以使用 + 进行拼接从而将变量嵌入字符串中,模板字符串使用 ${ } 形式将变量嵌入字符串中:

let?job?=?"程序员",?salary?=?"100";

//传统字符串拼接拼接
let?say?=?"我的工作是"?+?job?+?",?我每月可以挣"?+?salary?+?"大洋,真开心!";??

//模板字符串嵌入
say?=?`我的工作是${job},?我每月可以挣${job}大洋,真开心!`;???????????????????

????????${ }内部可以直接放入字符串也可以放入放入变量、表达式、对象、方法。如果大括号中的值不是字符串,将按照一般的规则转为字符串。比如,大括号中是一个对象,将默认调用对象的 toString() 方法。

4、解构赋值

????????解构赋值是对赋值运算符的扩展。他是一种针对数组或者对象进行模式匹配,然后对其中的变量进行赋值。

????????数组的解构赋值:

let?[a1,?a2,?a3]?=?[1,?2,?3];
console.log(`a1=${a1},a2=${a2},a3=${a3}`);
let?[b1,?,?b2]?=?[1,?2,?3];
console.log(`b1=${b1},b2=${b2}`);
let?[c1,?c2,?c3,?c4,?c5]?=?'hello';
console.log(`c1=${c1},c2=${c2},c3=${c3},c4=${c4},c5=${c5}`);

????????输出结果:

????????对象的解构赋值:

let?a1?=?{?x,?y?}?=?{?x:?'aaa',?y:?'bbb'?};
console.log(a1);??//a1.x='aaa',?a1.y='bbb'
let?a2?=?{?x:?['hello',?{?z:?'world'?}]?};
let?a3?=?{?x:?[y,?{?z?}]?}?=?a2;
console.log(a3);??//a3.x[0]='hello',?a3.x[1].z='world'

?????????输出结果:

????????解构默认值,当解构的对象的属性没有值甚至不存在时可以设置默认值:

let?[x?=?1,?y?=?2,?z?=?3]?=?[4,?undefined,?6];
console.log(`x=${x},y=${y},z=${z}`);
function?fun({?x?=?1,?y?=?2,?z?})?{
????console.log(`x=${x},y=${y},z=${z}`);
}
fun({});
fun({?x:?3?});
fun({?x:?4,?z:?5?});
fun({?x:?6,?y:?7,?z:?8?});
fun({?z:?9?});

?????????输出结果:

?5、展开运算符

????????展开运算符是三个点 ... ,能将数组转换为参数序列:

function?add(x,?y)?{
????return?x?+?y;
}
let?numbers?=?[1,?2];
console.log(add(...numbers));

????????输出结果:

????????与数组解构表达式结合,... 也可称为剩余运算符:

let?[a,?b,?...c]?=?[1,?2,?3,?4,?5,?6];
console.log(a,?b,?c);

?????????输出结果:

????????即 ...c 匹配数组除去前面确定的变量 a 和 b 后剩余的部分。

????????注意:与解构表达式结合时剩余运算符只能位于最后一个变量前,放在之前的变量前会抛出异常:

?let?[...a,?b,?c]?=?[1,?2,?3,?4,?5,?6]; 
//报错 Uncaught SyntaxError: Rest element must be last element
 let?[x,?...y,?z]?=?[1,?2,?3,?4,?5,?6]; 
//报错 Uncaught SyntaxError: Rest element must be last element

????????与对象解构表达式结合:

let { a, b, ...rest } = { a: 1, b: 2, c: 3, d: 4 };
console.log(a, b, rest);

? ? ? ? 输出结果:

?????????同样剩余运算符放在之前的变量前会抛出异常:

let?{?...rest,?a,?b?}?=?{?a:?1,?b:?2,?c:?3,?d:?4?}; 
//报错 Uncaught SyntaxError: Rest element must be last element

????????数组的拼接,使用 ... 运算符可以进行数组的拼接操作:

?let?a?=?[1,?2],?b?=?[4, 5];
?let?c?=?[...a,?...b];
 let d = 3;
 //单个元素加入拼接,对应变量无需使用 ... 运算符
 let e = [...a, d, ...b];
 console.log(c,e);

????????输出结果:

?????????对象的拷贝赋值。使用 ... 运算符可以将源对象拷贝到目标对象,拷贝后需注意字段值修改的作用范围:

let?src?=?{?user:?'admin',?password:?'123456',?job:?{?title:?'lawyer',?salary:?1000?}?};
let?tar?=?{?...src,?tel:?'110'?};
src.password?=?'888888';      //源单独修改
tar.user?=?'user';            //目标单独修改
src.job.title?=?'teacher';    //源和目标同步修改
tar.job.salary?=?200;         //源和目标同步修改
console.log(src,?tar);

????????输出结果:

????????可以看到非对象的属性修改,源和目标是独立互不影响的;对象属性的修改源和目标同步变化,因为对象的索引地址未发生变化。?

let tar = {...src };  //可以当做是src的浅拷贝

????????这种拷贝赋值的方法效果与 Object.assign() 相同:

let?src?=?{?user:?'admin',?password:?'123456',?job:?{?title:?'lawyer',?salary:?1000?}?},?tar={ tel:?'110' };
Object.assign(tar,?src);
src.password?=?'888888';
tar.user?=?'user';
src.job.title?=?'teacher';
tar.job.salary?=?200;
console.log(src,?tar);

????????输出结果:

?6、箭头函数

????????ES6之前,使用普通函数把数组每个字符串转换为大写形式:

const upperCaseStr = ['Hello',?'World'].map(function?(src)?{
????return?src.toUpperCase();
});

????????使用箭头函数:

const?upperCase?=?['Hello',?'World'].map(str?=>?str.toUpperCase());

? ? ? ? 通过对比可以发现代码书写上有了极大地简便。函数的参数只有一个,不需要使用 () 包起来,但是超过一个, 则必须需要将参数列表放在圆括号内:

const?add?=?(a,?b)?=>?a?+?b;

????????一般箭头函数都只有一个表达式作为函数主体,因此没有花括号 {} 且自动返回表达式,如果箭头函数内部需要多行代码,则需使用常规语法。按照常规语法上述箭头函数可按如下格式书写:

const upperCaseStr = ['Hello',?'World'].map(str?=>?{
????return?str.toUpperCase();
});
const?add?=?(a,?b)?=>?{
????return?a?+?b;
};

? ? ? ? 箭头函数对this的影响:对于普通函数, this 的值基于函数如何被调用:

function?Counter()?{
????this.count?=?0;
}
Counter.prototype.addCount?=?function?()?{
???setTimeout(function?()?{
????????this.count++;
????????console.log(`count:?${this.count}`);
????},?100);
}

const?counter?=?new?Counter();
counter.addCount();             //输出 count:?NaN

????????传递给 setTimeout() 的函数被调用时没用到 new、call() 或 apply(),也没用到上下文对象。意味着函数内的 this 的值是全局对象,而不是 counter 对象。实际上发生的情况是,在setTimeout调用的函数内部创建了新的 count 变量(默认值为 undefined),然后自增(undefined + 1 结果为 NaN)。

????????对于箭头函数,this 的值基于函数周围的上下文,this 的值和函数外面的 this 的值是一样的:

function?Counter()?{
????this.count?=?0;
}
Counter.prototype.addCount?=?function?()?{
    setTimeout(()?=>?{
????????this.count++;
????????console.log(`count:?${this.count}`);
????},?100);
}
const?counter?=?new?Counter();
counter.addCount();             //输出 count:?1

????????以上箭头函数中的 this 与外部的 this 值相同,都是指向调用的 counter 对象。

7、Promise

????????Promise是ES6中提供异步编程的解决方案,相比传统的通过回调函数和事件的方案更具有优越性,可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。

????????Promise共有三种状态:Pending(进行中),Resolved(已完成又称为Fulfilled),Rejected(已失败)。先看一个简单的使用示例:

new?Promise(
????function?(resolve,?reject)?{
????????let?score?=?Math.round(Math.random()?*?100);  //通常是耗时较长的异步操作。
????????console.log(`score:?${score}`);
????????if?(score?>=?60)?{
????????????resolve('pass');
????????}?else?{
????????????reject("fail");
????????}
????}
).then(function?resolveCallback(data)?{
????console.log(`resolved?data?:?${data}`);
},?function?rejectCallback(data)?{
????console.log(`reject?data?:?${data}`);
});

????????运行结果如下:

????????new Promise() 构造时的函数 function(resolve,?reject){} 用于处理异步操作。根据异步操作的结果通过调用 resolve() 和 reject() 设置 Promise 状态。then() 方法里第一个参数为处理 Resolved 状态的回调方法,第二个参数为处理 Rejected 状态的回调方法。

????????Promise 允许只设置 Resolved 状态,对应 then() 方法中也只需一个处理 Resolved 状态的回调方法:

new?Promise(
????(good)?=>?{
????????//?一些异步操作
????????good('pass');
????}
).then((data)?=>?{
????console.log(`resolved?data?:?${data}`);
});

?????????运行结果:

????????Promise 的状态只能被设置一次,多次的设置不会生效:

new?Promise(
????(pass,?fail)?=>?{
????????//?一些异步操作?
????????pass('pass');??//?设置状态为?Resolved??成功设置
????????fail('fail');??//?设置状态为?Rejected??不能成功设置
????}
).then((data)?=>?{
????console.log(`resolved?data?:?${data}`);
},?(data)?=>?{
????console.log(`reject?data?:?${data}`);
});

?????????运行结果:

?????????Promise 提供了 Promise.all 和 Promise.race 方法来处理多个 Promise 的问题。

????????Promise.all 将多个 Primise 实例合并成一个实例,只有当所有实例都变成 Resolved 状态才会执行回调:

const?p1?=?new?Promise((get)?=>?{
????setTimeout(()?=>?{
????????console.log('大王');
????????get("大王");
????},?200);
});
const?p2?=?new?Promise((get)?=>?{
????setTimeout(()?=>?{
????????console.log('小王');
????????get();
????},?100);
});
Promise.all([p1,?p2]).then(data?=>?{
????console.log(data);
????console.log('?王炸!');
});

????????运行结果:

????????其中 then() 里边的 data 为 Promise 实例数组 [p1,p2] 对应传递的参数数组 [data1,data2],data1 为 '大王' ,p2 没有传递参数 data2 为 undefined。

????????Promise.race 同样是将多个 Promise 实例包装成一个新的 Promise 实例, 多个实例中只要有一个实例状态改变,实例状态就改变了,返回的第一个改变的实例状态:

const?pTimeout?=?new?Promise((resolve)?=>?{
????setTimeout(()?=>?{
        console.log('pTimeout?resolve');
????????resolve({?code:?'TIMEOUT'?});
????},?100);
});
const?pRequest?=?new?Promise((resolve)?=>?{
????setTimeout(()?=>?{
        console.log('pRequest?resolve');
????????resolve({?code:?'OK',?data:?{}?});
????},?200);
});
Promise.race([p1,?p2]).then(res?=>?{
????if?(res.code?===?'OK')?{
????????console.log('request?ok');
????}?else?{
????????console.log('request?timeout');
????}
});

?????????运行结果:

?????????以上代码模拟接口数据请求处理请求超时的情况,pTimeout 设置超时时间 100 ms, pRequest 模拟数据请求200ms后返回数据,两个异步操作 pTimeout先状态改变, 打包的 Promise实例跟着改变,打印请求超时, 如果 pRequest 先于 pTimeout 改变状态则打印请求成功。

8、async, await

????????async 和 await 是用来处理异步的。即你需要异步像同步一样执行,需要异步返回结果之后,再往下依据结果继续执行。

????????async 是“异步”的简写,而 await 可以认为是 async wait 的简写。async 用于申明一个 function 是异步的,而 await 用于等待一个异步方法执行完成。

????????相比传统的回调方法和 Promise 写法,async-await 让我们书写代码时更加流畅,也增强了代码的可读性。

????????传统回调方式处理多异步流程:

    const?getUp?=?function?(callback)?{
????????????setTimeout(()?=>?{
????????????????console.log('get?up?at?7:00.')
????????????????callback();
????????????},?100);
????????}
????????const?washFace?=?function?(callback)?{
????????????setTimeout(()?=>?{
????????????????console.log('wash?face?at?7:10.')
????????????????callback();
????????????},?100);
????????}
????????const?brushTeeth?=?function?(callback)?{
????????????setTimeout(()?=>?{
????????????????console.log('brush?teeth?at?7:20.')
????????????????callback();
????????????},?100);
????????}
????????const?haveBreakfast?=?function?(callback)?{
????????????setTimeout(()?=>?{
????????????????console.log('have?breakfast?at?7:30.')
????????????????callback();
????????????},?100);
????????}
????????const?goToWork?=?function?()?{
????????????setTimeout(()?=>?{
????????????????console.log('go?to?work?at?8:00.')
????????????},?100);
????????}
????????const?happyDay?=?function?()?{
????????????getUp(function?()?{
????????????????washFace(function?()?{
????????????????????brushTeeth(function?()?{
????????????????????????haveBreakfast(function?()?{
????????????????????????????goToWork();
????????????????????????});
????????????????????});
????????????????});
????????????});
????????}
????????happyDay();

????????运行结果:

?Promise 处理多异步流程:

const?getUp?=?function?()?{
????????????return?new?Promise((resolve)?=>?{
????????????????setTimeout(()?=>?{
????????????????????console.log('get?up?at?7:00.')
????????????????????resolve();
????????????????},?100);
????????????});
????????}
????????const?washFace?=?function?()?{
????????????return?new?Promise((resolve)?=>?{
????????????????setTimeout(()?=>?{
????????????????????console.log('wash?face?at?7:10.')
????????????????????resolve();
????????????????},?100);
????????????});
????????}
????????const?brushTeeth?=?function?()?{
????????????return?new?Promise((resolve)?=>?{
????????????????setTimeout(()?=>?{
????????????????????console.log('brush?teeth?at?7:20.')
????????????????????resolve();
????????????????},?100);
????????????});
????????}
????????const?haveBreakfast?=?function?()?{
????????????return?new?Promise((resolve)?=>?{
????????????????setTimeout(()?=>?{
????????????????????console.log('have?breakfast?at?7:30.')
????????????????????resolve();
????????????????},?100);
????????????});
????????}
????????const?goToWork?=?function?()?{
????????????return?new?Promise((resolve)?=>?{
????????????????setTimeout(()?=>?{
????????????????????console.log('go?to?work?at?8:00.')
????????????????????resolve();
????????????????},?100);
????????????});
????????}
????????const?happyDay?=?function?()?{
????????????getUp().then(washFace()).then(brushTeeth()).then(haveBreakfast()).then(goToWork());
????????}
????????happyDay();

????????运行结果:

????????注意:因为Promise在构造的时候就会被立即执行,所以以上代码采用 const p = function(){return new Promise()} 的方式进行定义,才能满足在需要调用时才执行的需求。

????????async, await 处理多异步流程:

const?getUp?=?function?()?{
????????????return?new?Promise((resolve)?=>?{
????????????????setTimeout(()?=>?{
????????????????????console.log('get?up?at?7:00.')
????????????????????resolve();
????????????????},?100);
????????????});
????????}
????????const?washFace?=?function?()?{
????????????return?new?Promise((resolve)?=>?{
????????????????setTimeout(()?=>?{
????????????????????console.log('wash?face?at?7:10.')
????????????????????resolve();
????????????????},?100);
????????????});
????????}
????????const?brushTeeth?=?function?()?{
????????????return?new?Promise((resolve)?=>?{
????????????????setTimeout(()?=>?{
????????????????????console.log('brush?teeth?at?7:20.')
????????????????????resolve();
????????????????},?100);
????????????});
????????}
????????const?haveBreakfast?=?function?()?{
????????????return?new?Promise((resolve)?=>?{
????????????????setTimeout(()?=>?{
????????????????????console.log('have?breakfast?at?7:30.')
????????????????????resolve();
????????????????},?100);
????????????});
????????}
????????const?goToWork?=?function?()?{
????????????return?new?Promise((resolve)?=>?{
????????????????setTimeout(()?=>?{
????????????????????console.log('go?to?work?at?8:00.')
????????????????????resolve();
????????????????},?100);
????????????});
????????}
????????const?happyDay?=?async?function?()?{
????????????await?getUp();
????????????await?washFace();
????????????await?brushTeeth();
????????????await?haveBreakfast();
????????????await?goToWork();
????????}
????????happyDay();

????????运行结果:

? ? ? ? 对比一下代码方式,明显async, await的方式要更简洁易读。?

?

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-06-29 18:55:53  更:2022-06-29 18:58:00 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/11 9:50:36-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码