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);
}
})()