ES6 介绍
ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。
为什么要学习 ES6
- ES6 的版本变动内容最多,具有里程碑意义
- ES6 加入许多新的语法特性,编程实现更简单、高效
- ES6 是前端发展趋势,就业必备技能
ES6新增部分
let 和 const
ES6 新增了let
命令,用来声明变量。它的用法类似于var
,但是所声明的变量,只在let
命令所在的代码块内有效。
{
let a = 10;
var b = 1
}
console.log(a)
console.log(b)
上面代码在代码块之中,分别用let
和var
声明了两个变量。然后在代码块之外调用这两个变量,结果let
声明的变量报错,var
声明的变量返回了正确的值。这表明,let
声明的变量只在它所在的代码块有效。 而var 声明变量进行了变量提升
let 不存在变量提升
var
命令会发生“变量提升”现象,即变量可以在声明之前使用,值为undefined
。这种现象多多少少是有些奇怪的,按照一般的逻辑,变量应该在声明语句之后才可以使用。 let
命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错。
// var 的情况
console.log(foo);
var foo = 2;
// let 的情况
console.log(bar);
let bar = 2;
let不允许重复声明
function func() {
let a = 10;
var a = 1;
}
function func() {
let a = 10;
let a = 1;
}
const命令
const
声明一个只读的常量。一旦声明,常量的值就不能改变。 const
声明的变量不得改变值,这意味着,const
一旦声明变量,就必须立即初始化,不能留到以后赋值。
const a = 3.1415;
console.log(a) // 3.1415
a = 3;
// TypeError: Assignment to constant variable.
const
的作用域与let
命令相同:只在声明所在的块级作用域内有效。
解构赋值
ES6 允许按照一定模式从数组和对象中提取值,对变量进行赋值,这被称为解构赋值
1. 数组的结构
const F5 = ['小沈阳','刘能','赵四','宋小宝','安玲玲'];
let [xiao, liu, zhao, song,an] = F5;
console.log(xiao);
console.log(liu);
console.log(zhao);
console.log(song);
2. 对象的解构
const zhao = {
name: '赵本山',
age: '不详',
xiaopin: function(){
console.log("我可以演小品");
}
};
let {name, age, xiaopin} = zhao;
console.log(name);
console.log(age);
console.log(xiaopin);
xiaopin();
字符串的扩展
模板字符串
ES6 引入新的声明字符串的方式 『``』
- 声明
let str = `我也是一个字符串哦!`;
console.log(str, typeof str);
- 内容中可以直接出现换行
es6: let str = `<ul> 传统:let str = '<ul>'+
<li>沈腾</li> '<li>沈腾</li>'+
<li>玛丽</li> '<li>沈腾</li>'+
<li>魏翔</li> '<li>魏翔</li>'+
<li>艾伦</li> '<li>魏翔</li>'+
</ul>`; ' </ul>';
- 变量拼接
let lovest = '魏翔';
let out = `${lovest}是我心目中最搞笑的演员!!`;
console.log(out);
函数扩展
rest 参数 ES6 引入 rest 参数,用于获取函数的实参,用来代替 arguments
// ES5 获取实参的方式
function date(){
console.log(arguments);
}
date('白芷','阿娇','思慧');
// rest 参数
function date(...args){
console.log(args);
}
date('阿娇','柏芝','思慧');
// rest 参数必须要放到参数最后
function fn(a,b,...args){
console.log(a);
console.log(b);
console.log(args);
}
fn(1,2,3,4,5,6);
箭头函数 ES6 允许使用“箭头”(=>
)定义函数。
var f = v => v;
// 等同于
var f = function (v) {
return v;
}
//声明一个函数
let fn = function(){}
let fn = (a,b) => {
return a + b;
}
//调用函数
let result = fn(1, 2);
console.log(result);
//1. this 是静态的. this 始终指向函数声明时所在作用域下的 this 的值
function getName(){
console.log(this.name);
}
let getName2 = () => {
console.log(this.name);
}
//设置 window 对象的 name 属性
window.name = '尚硅谷';
const school = {
name: "ATGUIGU"
}
//直接调用
getName();
getName2();
//call 方法调用
getName.call(school);
getName2.call(school);
//2. 不能作为构造实例化对象
let Person = (name, age) => {
this.name = name;
this.age = age;
}
let me = new Person('xiao',30);
console.log(me);
//3. 箭头函数的简写
1) 省略小括号, 当形参有且只有一个的时候
let add = n => {
return n + n;
}
console.log(add(9));
2) 省略花括号, 当代码体只有一条语句的时候, 此时 return 必须省略
而且语句的执行结果就是函数的返回值
let pow = n => n * n;
console.log(pow(8));
箭头函数练习
- 点击 div 2s 后颜色变成『粉色』
- 从数组中返回偶数的元素
展开运算符 […]
第一个叫做 展开运算符(spread operator),作用是和字面意思一样,就是把东西展开。可以用在array
和object
上都行。
比如:
let a = [1,2,3];
console.log(...a)
let b = [0, ...a, 4]; // [0,1,2,3,4]
let obj = { a: 1, b: 2 };
let obj2 = { ...obj, c: 3 }; // { a:1, b:2, c:3 }
let obj3 = { ...obj, a: 3 }; // { a:3, b:2 }
Es6模块化
模块功能主要由两个命令构成:export
和import
。export
命令用于规定模块的对外接口,import
命令用于输入其他模块提供的功能。
一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用export
关键字输出该变量。下面是一个 JS 文件,里面使用export
命令输出变量。
// profile.js
//分别暴露
export var firstName = 'Michael';
export var lastName = 'Jackson';
export var year = 1958;
export
的写法,除了像上面这样,还有另外一种。
// profile.js
//统一暴露
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;
export { firstName, lastName, year };
export
最后一种写法
//默认暴露
export default {
school: 'ATGUIGU',
change: function(){
console.log("我们可以改变你!!");
}
}
使用export
命令定义了模块的对外接口以后,其他 JS 文件就可以通过import
命令加载这个模块。
// main.js
import { firstName, lastName, year } from './profile.js';
function setName(element) {
element.textContent = firstName + ' ' + lastName;
}
上面代码的import
命令,用于加载profile.js
文件,并从中输入变量。import
命令接受一对大括号,里面指定要从其他模块导入的变量名。大括号里面的变量名,必须与被导入模块(profile.js
)对外接口的名称相同。
如果想为输入的变量重新取一个名字,import
命令要使用as
关键字,将输入的变量重命名。
import { lastName as surname } from './profile.js';
export default 命令
// export-default.js
export default function foo() {
console.log('foo');
}
// 或者写成
function foo() {
console.log('foo');
}
export default foo;
下面比较一下默认输出和正常输出。
// 第一组
export default function crc32() { // 输出
// ...
}
import crc32 from 'crc32'; // 输入
// 第二组
export function crc32() { // 输出
// ...
};
import {crc32} from 'crc32'; // 输入
上面代码的两组写法,第一组是使用export default
时,对应的import
语句不需要使用大括号;第二组是不使用export default
时,对应的import
语句需要使用大括号。
export default
命令用于指定模块的默认输出。显然,一个模块只能有一个默认输出,因此export default
命令只能使用一次。所以,import命令后面才不用加大括号,因为只可能唯一对应export default
命令。
ES6 promise
回调地狱
先了解一下回调地狱
第一种没有产生回调地狱之前
形成回调地狱
就是一个函数要去拿另一个函数内部去拿他的属性—<注意:闭包也有这个意思,但是闭包是在外部执行了,在另一个函数内部做返回处理>,且该函数在另一个函数内部做执行,一次外部函数一个接一个放到另一个函数内部去拿值,第一层失败下面全部失败。
实例化Promise
1.什么是Promise
Promise 是异步编程的一种解决方案,其实是一个构造函数,自己身上有all、reject、resolve这几个方法,原型上有then、catch等方法。(ps:什么是原型:https://blog.csdn.net/qq_34645412/article/details/105997336)
Promise对象有以下两个特点。
(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、resolved(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为resolved和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。下面先new一个对象
//实例化 Promise 对象
const p = new Promise(function(resolve, reject){
setTimeout(function(){
let data = '数据库中的用户数据';
resolve(data);
//let err = '数据读取失败';
//reject(err);
}, 1000);
});
//调用 promise 对象的 then 方法
p.then(function(value){
console.log(value);
}, function(reason){
console.error(reason);
})
刷新页面会发现控制台直接console出来
其执行过程是:执行了一个异步操作,也就是setTimeout,2秒后,输出“执行完成”,并且调用resolve方法。
注意!我只是new了一个对象,并没有调用它,我们传进去的函数就已经执行了,这是需要注意的一个细节。所以我们用Promise的时候一般是包在一个函数中,在需要的时候去运行这个函数,如:
<div onclick='promiseClick()'>开始异步请求</div>
const promiseClick =()=>{
console.log('点击方法被调用')
let p = new Promise(function(resolve, reject){
//做一些异步操作
setTimeout(function(){
console.log('执行完成Promise');
resolve('要返回的数据可以任何数据例如接口返回数据');
}, 2000);
});
return p
}
resolve是个什么鬼
我们包装好的函数最后,会return出Promise对象,也就是说,执行这个函数我们得到了一个Promise对象。接下来就可以用Promise对象上有then、catch方法了,这就是Promise的强大之处了,看下面的代码:
promiseClick().then(function (data) {
console.log(data);
//后面可以用传过来的数据做些其他操作
//......
})
先是方法被调用起执行了promise,最后执行了promise的then方法,then方法是一个函数接受一个参数是接受resolve返回的数据这事就输出了‘要返回的数据可以任何数据例如接口返回数据’
这时候你应该有所领悟了,原来then里面的函数就跟我们平时的回调函数一个意思,能够在promiseClick这个异步任务执行完成之后被执行。这就是Promise的作用了,简单来讲,就是能把原来的回调写法分离出来,在异步操作执行完后,用链式调用的方式执行回调函数。
你可能会觉得在这个和写一个回调函数没有什么区别;那么,如果有多层回调该怎么办?如果callback也是一个异步操作,而且执行完后也需要有相应的回调函数,该怎么办呢?总不能再定义一个callback2,然后给callback传进去吧。而Promise的优势在于,可以在then方法中继续写Promise对象并返回,然后继续调用then来进行回调操作。
所以:精髓在于:Promise只是能够简化层层回调的写法,而实质上,Promise的精髓是“状态”,用维护状态、传递状态的方式来使得回调函数能够及时调用,它比传递callback函数要简单、灵活的多。
reject的用法
以上是对promise的resolve用法进行了解释,相当于resolve是对promise成功时候的回调,它把promise的状态修改为fullfiled,那么,reject就是失败的时候的回调,他把promise的状态修改为rejected,这样我们在then中就能捕捉到,然后执行“失败”情况的回调。
function promiseClick(){
let p = new Promise(function(resolve, reject){
setTimeout(function(){
var num = Math.ceil(Math.random()*20); //生成1-10的随机数
console.log('随机数生成的值:',num)
if(num<=10){
resolve(num);
}
else{
reject('数字太于10了即将执行失败回调');
}
}, 2000);
})
return p
}
promiseClick().then(
function(data){
console.log('resolved成功回调');
console.log('成功回调接受的值:',data);
},
function(reason){
console.log('rejected失败回调');
console.log('失败执行回调抛出失败原因:',reason);
}
);
catch的用法
与Promise对象方法then方法并行的一个方法就是catch,与try catch类似,catch就是用来捕获异常的,也就是和then方法中接受的第二参数rejected的回调是一样的,如下:
function promiseClick(){
let p = new Promise(function(resolve, reject){
setTimeout(function(){
var num = Math.ceil(Math.random()*20); //生成1-10的随机数
console.log('随机数生成的值:',num)
if(num<=10){
resolve(num);
}
else{
reject('数字太于10了即将执行失败回调');
}
}, 2000);
})
return p
}
promiseClick().then(
function(data){
console.log('resolved成功回调');
console.log('成功回调接受的值:',data);
}
)
.catch(function(reason){
console.log('catch到rejected失败回调');
console.log('catch失败执行回调抛出失败原因:',reason);
});
封装ajax
// Promise 封装 ajax
function fetch(method, url, data){
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
xhr.open(method, url, true);
if(data!=null){
// 视情况添加请求头
xhr.send(data);
}else{
xhr.send();
}
xhr.onreadystatechange = function() {
if(xhr.status === 200 && xhr.readyState === 4){
resolve(xhr.responseText);
} else {
reject(xhr.responseText);
}
}
})
}
// 使用
fetch("GET", "/some/url.json", null)
.then(result => {
console.log(result);
}).catch(error=>{
console.log(error);
})
// 视情况添加请求头
xhr.send(data);
}else{
xhr.send();
}
xhr.onreadystatechange = function() {
if(xhr.status === 200 && xhr.readyState === 4){
resolve(xhr.responseText);
} else {
reject(xhr.responseText);
}
}
})
}
// 使用
fetch(“GET”, “/some/url.json”, null)
.then(result => {
console.log(result);
}).catch(error=>{
console.log(error);
})