ES6-11 学习笔记
学习ES5-11S时候做的笔记,第一遍过注重各个新特性的用法,实际案例在将来开发中遇到将会补充上来
看这篇文章的小伙伴需要有一定的js基础
文章目录
(零)ES概述
1. 什么是ES
- ES:EcmaScript 是脚本语言的
规范
,JS就是ES的一种实现
- 新的ES就有新特性
2.为什么要学习新特性
- 前端框架要用,学好新特性才能用好框架
- 语法简单,功能丰富
- ES6 变动内容最多,有里程碑意义!
(一) 声明变量
1. let
- 声明语法
let a;
let b=123
let c=4,5=7
- 变量不能重复声明
- 块级作用域:变量只在{} 之中有效,出了就无效了
{
let person="szk"
}
console.log(person) //是识别不到person变量的
对于if() for() 括号中的也属于块级作用域
- 不影响作用域链:代码块里面可以读取到外部的变量
{
let person="szk";
function f1(){
console.log(person)
//在function的代码块中用到外部的变量可以出了{}向上寻找
}
}
2. let和var的区别
- var是全局作用域,let是块级作用域
- 不存在变量提升:就是变量的使用必须在声明后,var则会先搜集变量统一先赋值undefined
3. const
- 声明常量用const
- 一定要赋
初始值
- 常量值不能修改
- 常量用
大写
(潜规则) - 常量对于数组和对象的修改,不算
对常量的修改
,不会报错
const team = ['szk','szk2']
team.push('shadder2k')
//因为team指向的内存地址没有修改,不会报错
(二)解构
- 可以将对象/数组中的值更方便地取出
- let {对象中的属性1,属性2 … }=对象
let person={
name:"szk",
age:18,
playGame:function(){
console.log("hello")
}
}
//声明了一个对象,接下来用解构去取值
let {name,age,playGame}=person
console.log(name)
console.log(age)
console.log(playGame)
playGame()
最终结果
(三) 字符串模板
1.声明
- 以前的声明是用:单引号或者双引号
- es6中可以使用反引号 ``
2. 好处
- 可以不用复杂的拼接,直接换行也不报错
- 可以使用
${变量名}
在字符串中拼接
//使用反引号``声明
let str1=`abc`
//可以在字符串中换行,以前换行要用+拼接
//用单引号或双引号这样写是违法的,反引号就合法了
let str2=`<div>
<li>szk<li>
</div>`
// 使用${变量},可以在字符串中直接嵌入变量,不用+拼接
let str3=`overWatch`
let str4=`${str3}准备出新作了`
(四)对象声明的简化
- 对象中想声明和外部变量同名的属性时,可以简化
let name="szk";
let age=4;
let walk=function(){
console.log("walk");
}
//在声明对象的时候,对于属性和外部变量相同的
let person={
//不用写 name:name
name,
age,
walk
}
(五)箭头函数
1. 声明
- let 函数名=(虚参)=>{}
let fun1=()=>{
console.log("hello);
}
//等价于
let fun2=function(){
console.log("hi");
}
2. 和传统声明函数的区别
(1) this的指向不同
-
箭头函数没有自己的this,它的this继承自他的父级,跟调用者无关
-
传统函数的this是调用者
-
箭头函数
定义在全局或者对象中,this最终都指向的是window
-
箭头函数
定义在类中,this指向最终实例化这个类的对象
(2)不能作为构造实例化对象
(3)不能获取arguments
3. 应用场景
- 例子需求:点击一下方块,延迟两秒变粉色
- 如果用function作为setTimeout中的函数,是不行的,因为调用者是window,this没有指向这个div
- 如果这里用的箭头函数,则this指向的是div,就可以完成
- 综上,记住
箭头函数没有自己的this,它的this继承自他的父级,跟调用者无关
,来根据具体需求判断使用哪种 - 如果函数中的this需要用到调用对象,使用匿名function
- 如果函数中的this需要指向父级的this,使用箭头函数,比如使用setTimeout这种调用者是window的,就用匿名函数简单
4. 函数与解构结合
- 如果函数传进来的参数是个对象,可以用{}直接解构对象里的内容
- 没传的可以有默认值
- 传多了也没关系
let person={
name:"szk",
age:4
}
function fun1({name,age,grade=1}){
console.log(name);
console.log(age);
}
fun1(person)
(六)原型Symbol
- js中的第七种数据类型,表示
独一无二的值
- Symbo值唯一,解决命名冲突的问题
- Symbol不能与其他数据进行运算
1.创建方式
- 第一种方式:Symbol(“symbol名字”)创建
- 就算名字相同,也是两个不同的Symbol
let s=Symbol()
//可以给它打上标签
let s2=Symbol("szk1")
let s3=Symbol("szk2")
//标签可以相同,但s3和s4是不同的Symbol,可以理解为名字可以相同但身份证号不同
let s4=Symbol("szk2")
- 第二种方式:Symbol.for(“symbol名字”)
- 这种方式创建的如果名字相同,则symbol指向同一个
let s5=Symbol.for("szk5")
let s6=Symbol.for("szk5")
console.log(s5 === s6) //他俩是一样的
Symbol.keyfor(s5) //szk5,用来查找这个Symbol的名字
2.使用
- Symbol是独一无二的,可以用
往对象中添加新的属性
,因为添加之前,你可能不知道你同事写的很复杂的对象中有没有和你重名的属性
,用symbol的唯一性可以保证你安全地添加属性
- 把不需要对外操作和访问的属性用Symbol定义,因为Symbol的key不能通过Object.key显示出来
- 在对象中用Symbol表示键需要用
[]
括起来 - 取对象中的Symbol的属性,不用
.
而是用[]
let s1=Symbol("grade");
let s2=Symbol("school")
let person={
name:"szk",
age:99,
//用中括号括起来外部的Symbol变量名
[s1]:"12",
[s2]:"NUIST",
//直接在里面声明也要用[]括起来
[Symbol("home")]:"DG"
}
//获取对象中属性名是Symbol的用[],而不是.
console.log(person[s1]);
(七)迭代器
1. 是什么
- 迭代器是
为不同数据结构提供统一的访问机制
- 任何数据结构只要部署了iterator接口,就可以完成遍历操作
- js中原生具备iterator接口的数据
- js中迭代器供
for of
来使用
2.工作原理
- 自定义一个迭代器就可以明白了
- 例子需求:迭代一个对象中的数组,普通的对象是不能用
for of
循环遍历的,编译器是这样提示的
那就按他的要求写上这个方法
let class01={
name:"class01",
student:["szk1","szk2","szk3"],
[Symbol.iterator](){
//创建一个“指针”
let index=0;
//要返回一个对象
return {
//对象中要有next方法
next:()=>{
if(index<this.student.length){
//只要没遍历完,指针向后移一个,返回当前指针的valuse值
return {value:this.student[index],done:false}
index++;
}else{
return {value:undefined,done:true}
}
}
}
}
}
for(let item of class01){
console.log(item);
}
- 对象中写了这个自定义的迭代器后,就可以按照我们的需求来进行迭代
(八)生成器
1. 什么是生成器
- 生成器就是一种有点不同的函数
- 其实是个
特殊的迭代器
- 可以用来
异步编程
2.如何定义
- function
*
函数名字(){} 就是function后加一个*
- yield是ES6的新关键字,使生成器函数执行暂停,yield关键字后面的表达式的值返回给生成器的调用者。它可以被认为是一个基于生成器的版本的return关键字。
- yield关键字实际返回一个迭代器对象,它有两个属性,value和done,分别代表返回值(yield表达式求值的结果)和是否完成。
function * generator(){
console.log("1")
yield "第一块代码"
console.log("2")
yield "第二块代码"
console.log("3")
yield "第三块代码"
console.log("4")
}
3.如何执行
- 和普通函数的调用有区别
- 使用迭代器执行
每一块
代码
function * generator(){
console.log("1")
yield "第一块代码"
console.log("2")
yield "第二块代码"
console.log("3")
yield "第三块代码"
console.log("4")
}
let iterator=generator();
iterator.next() //就可以以yield作为分隔符一段一段的执行,且next方法返回的是分隔符的内容
iterator.next()
iterator.next()
iterator.next() //此处三个分隔符将函数分为了四段
for(i of generator){
console.log(i) //通过for of 也可以遍历执行生成器
}
4. 生成器传参
- next方法中可以传参,传的参数作为yield的返回值
function * gen(){
const data= yield
console.log(data) // hello
}
iterater,next(“hello”) //这样传参,这个yield的返回值就会是这个参数
5. 生成器案例
- 例子需求:三个延迟函数依次调用,传统方法写回调函数,堪称回调地狱,这里使用生成器来解决这个问题
- 生成器中可以
用yield 调用三个函数,在各个函数内部,可以用next方法调用到下一个函数
function getUser(){
setTimeout(()=>{
console.log('获取用户数据');
let data="用户数据";
iterator.next(data); //在各自函数中触发下一个的执行
},1000)
}
function getGoods(){
setTimeout(()=>{
console.log('获取商品');
let data="商品信息";
iterator.next(data);
},1000)
}
function getOrder(){
setTimeout(()=>{
console.log('获取订单信息');
let data="订单信息";
iterator.next(data);
},1000)
}
function * generator(){
//在函数中调用iterator.next(data),参数data将作为的返回值返回给当前调用的yield
let user=yield getUser();
console.log("user");
let goods=yield getGoods();
console.log("goods");
let order=yield getOrder();
console.log("order");
}
let iterator=generator();
iterator.next(); //调用了第一个fun1(),fun1()中又有iterator.next(),会继续调用第二个,以此类推
(八)Promise
- promise是一个对异步操作进行封装并返回其结果的构造函数
- 使代码更加简洁和避免回调地狱
1.promise的基本结构
//实例化一个promise对象
let promise=new Promise((resolve,reject)=>{
//构造的时候用一个方法构造,参数为resolve,reject
//业务代码
//调用resolve可以使promise的状态变为成功
resolev();
//调用reject可以使promise的状态变为失败
reject();
})
//调用then方法,参数分别是状态成功时的回调函数,一个是状态失败时的回调函数
promise.then((result)=>{},(error)=>{})
2. 使用例子(axios的封装)
3. then方法的返回值
- then方法的返回值也为一个promise对象
- 如果回调函数中返回一个
非promise对象
,则then的返回promise的状态为成功
- 如果回调函数中返回的是
promise对象
,则then的返回promise的状态根据回调函数中的promise对象状态而定
- 如果回调函数中
抛出错误 throw new Error('出错啦')
,则then的返回promise的状态为错误
- 因此
then方法可以链式下去
promise.then(resut=>{
return new Promise((resolve,reject)=>{
})
},error=>{}).then().then().then() //.....可以一直链式下去
(九)集合 Set
- set是es6中新加入的数据结构
- set
类似没有重复数据的数组
1. set的基本操作
- 创建
let s = new Set()
//参数是一个可迭代对象,比如数组
let s1=nre Set(['szk1','szk2','szk3'])
- 增
s1.add('szk4')
- 删
s1.delete('szk1')
- 检测
s1.has('szk2')
- 清空
s1.clear()
2. 应用
- 数组去重:将数组转换为集合,再转换为数组
let arr1=[1,1,2,3,3,4,5,6];
//变成集合后用...拓展运算符将其展开为序列,之后再变成数组即可
arr1=[...new Set(arr1)]
- 取交集:先合并再去重
let s1=new Set([1,2,3,4,5])
let s2=new Set([1,2,7,8,9])
let s3=new Set([..s1,...s2])
- 取差集:用filter函数过滤
(十)扩展运算符
- 扩展运算符
...
1. 作用
- 可以将数组,集合等转换为一个参数序列,可以用于函数传参
let arr=[1,2,3,4,5]
console.log(...arr);
// 1 2 3 4 5
function fun1(){
console.log(arguments)
}
fun1(...arr)
//这就相当于 fun1(1,2,3,4,5)
- 可以合并数组
let arr1=[1,2,3]
let arr2=[5,6,7]
let arr3=[...arr1,...arr2]
(十一) map
- map可以理解成一个个键值对,且键不能重复
- js 弱类型中,键和值是弱类型的,都是any,什么数据类型都可以
1. 使用
- 创建
//创建一个Map对象
let m=new Map();
- 增:map.set(key,value) 可以任何数据类型set进去
let m=new Map();
m.set('age',123)
//可以是函数
m.set('add',function(a,b){return a+b})
//可以是对象,可以是数组
let person={name:"szk",age:10};
m.set(person,[1,2,3])
- 删:
- m.delete(key)
- m.clear() 清空
- 改:m.set()
//和增一样,想改的key之后跟更新的value即可
m.set(key.value)
- 查:
- m.get(key)
m.get(key)
m.get("age")
//如果键是个对象,就写对象的变量名
m.get(person)
- m.size() 查看大小
- for(item of map) for of 遍历
(十二)数值扩展
1. Number.EPSILON
- Number.EPSILON是js的
最小精度
,小于这个就无法判断谁大谁小了 - 它的值接近于 2.2204E-16 是个非常小的数
2. 二进制和八进制和十六进制
- 0b开头就是二进制
- 0o开头八进制
- 0x开头十六进制
let b=0b1010;
let o=0o777;
let x=0xfff;
let d=100
//四种都表示100
3.一些别的方法
- Number.isFinite() 是否为有限数
- Number.isNan() 是否为Nan
- Number.parseInt(‘’) Number.parseFloadt(‘’) 将字符串转为数
- Math.trunc() 将数字的小数部分抹去
- Math.sign() 判读一个数是正数,负数,还是0 ,返回值分别为1 0 -1
(十三)ES6的模块化
1. 好处
- 防止命名冲突
- 代码复用
- 高维护性
2. export三种方式
- export用来向外暴露
- import用来引入
方法一
- 需要引入的东西前加
export
关键字
方法二
- 在js中用
export default {}
包裹,就是默认暴露 - 暴露的是对象
方式三
- 在js结尾统一暴露
export {需要暴露的东西}
3. import的几种方式
第一种
- 通用方式
import * as 别名 from 路径
import * as m1 from './m1.js'
第二种
- 解构形势
import {解构出来的名字} from 路径
import {school,student} from './m1.js'
//不能重名,引入时可以有别名
import {school as school_2 } from './m2.js'
console..log(school) //解构完就可以在后面直接使用了
//对于默认暴露
import {default as m3} from './m3.js'
第三种:只对于默认暴露的简化形式
import m3 from './m3.js'
(十四)async和await
- 用来写异步代码的
- async函数返回值为
promise
对象 - promise的结果由
async函数执行的返回值决定
1. async
- 放在
函数之前
,就可以声明一个async函数
async function fun1(){
}
- async返回的是一个promise对象,promise对象的状态由
函数中的返回值决定
- 如果函数返回值为
非promise对象
,则promise状态为正常
- 如果函数返回值是一个 new Error() 则
promise状态为错误
- 如果函数返回是一个promise对象,则
promise状态跟返回值的promise对象状态相同,值就是返回的promise的值
- 如果函数返回值为
- 因为返回的是promise对象,因此可以
链式then下去
2. await
- await
必须写在async函数中
- await右侧表达式一般为promise对象
- await 返回的是promise
成功的值
- await的 promise如果失败了,会
抛出异常
,需要用try catch处理
let p = new Promise((resolve,reject)=>{
resolev("success")
})
async fun1(){
// await 后面放promise对象
result=await p;
//这里是成功的,所以result就是promise成功的值:success
}
- 如果是失败的
let p = new Promise((resolve,reject)=>{
reject("error")
})
async fun1(){
try{
// await 后面放promise对象
result=await p;
}catch(e){
//如果失败了就会抛出异常,需要try catch
console.log(e)
}
}