ES6的特点
模块化
初始化项目 : npm init 选项可全部回车
初始化后,会生成package.json文件,里面存放了第三方包
快速初始化项目 : npm i -y 表示全部的选项都是yes
package.json文件
devDependencies
在产品阶段使用的包
Dependencies
在开发阶段使用的包
安装第三方包的工具,包管理工具/机制
npm
国外的包管理工具 服务器部署在外网 下载速度会比较慢,但包比较全,
不会加载缓存,直接重新下载依赖
cnpm
国内的包管理工具,服务器部署在国内 下载速度比较快
不会加载缓存,直接重新下载依赖
安装
npm config set registry https://registry.npmmirror.com/
npm install -g cnpm --registry=https://registry.npmmirror.com
// 项目中配置映射修改规则
npm.taobao.org => npmmirror.com
registry.npm.taobao.org => registry.npmmirror.com
yarn
会先加载缓存查看是否存在,不存在再继续下载。
安装
npm install -g yarn --registry=https://registry.npmmirror.com
yarn -v 查看版本号
全局安装与局部安装
npm install -g 包名
npm install --save 包名
模块化规范
模块化的导出
列表导出
格式:
ES6: export { 导出的第一个变量,导出的第二个变量 }
ES5: exports { 导出的第一个变量名: 变量值,导出的第二个变量名: 变量值 }
重命名导出
格式:
export { 导入的变量名 as 要重名为的名字}
默认导出
格式:
export default {
导出的名字:导出的值
}
模块化的导入
列表导入
ES6:
格式:
import {导出的变量名,导出的第二个变量名} from '导入文件的路径'
直接使用 导出的变量名,就直接可以使用我们导出的变量
ES5:
格式:
let 模块名 = require('模块路径')
模块名.导出的变量名
重命名导入
格式:
import {导出的变量名 as 重命名} from '导入文件的路径'
默认导入
格式 : import 自定义的名字 from ’导入的模块路径‘
全部引入
import * as 自定义命名 from '路径'
CommonJs模块规范(是node的一个规范)
导出:
module.exports = {变量,变量}
或
module.exports.变量 = xxx;
导入:
let mokuai = require('路径');
mokuai.变量;
导入第三方包:
let lodash = require('包名') // 注意,首先保证该包已npm下载
或
let {变量,变量}= require('路径');
特点:
运行时,导出的是一个值的赋值,即是浅拷贝,与es6的不同,es6输出的是一个值得引用,即在导出后,再对模块里的数据进行修改,那么引入的值也会被修改。
例:
导出模块
export let name = ’zhangsan‘;
setTimeout = (()=> name = 'lisi',2000);
导入模块
import name from ’/path‘,//name 两秒后变成lisi
commentjs在运行时才会加载模块,ES6在编译时就会加载我们的模块
ES6 与 CommonJs 的区别
1. commonJS 导出的值为浅拷贝 , ES6为深拷贝,即值得引用
2. commonJS在运行时加载模块,ES6在编译时加载模块
第三方包
babel-cli 转码工具
当某些浏览器不支持高版本的es语法时或低版本的node不支持时,需要转码
安装
指令
npm install -g babel-cli // 全局安装
局部安装 cnpm install --save-dev babel-cli babel-preset-latest
--save为局部开发环境安装
-dev为上线环境安装
babel-preset-latest 预设
测试安装 : babel --version
使用
注意使用前需要局部安装 :
cnpm install --save-dev babel-cli babel-preset-latest
在文件夹根目录下创建文件 .babelrc
设置文件
{
“presets”: [“latest”]
}
最后在控制台 : babel xxx.js 即可成功转换该js文件
将转码后的文件输出给另一个文件
babel xxx.js --out-file 要输出的文件名.js
将当前文件夹全部的js文件 转码到另一个文件夹里面
babel 当前要转换的文件夹名 --out-dir 要转换到的另一个文件夹名字
箭头函数
没有this指向,this指向的是声明箭头函数时外部的作用域
案例
1.
let name = 'zhangsan'
sayName=()=>{
console.log(this.name); //undefined
}
注意!! 该this指向的是一个外部作用域,以上案例即当前模块module,如果moudule为一个空对象,那么就是undefined。默认情况下,指向的 module.exports,注意默认情况下 exports与module.exports指向的是同一个对象。
实参数组 rest
用rest来保存形式参数,当没有形式参数来接受实际参数时,那么传过来的实际参数都被保存在rest里面,如:
let test = (a,...b)=>{}
test(1,2,3,4)
以上rest里面的保存的是...b ,a将不会被保存
普通函数与箭头函数的区别
1.this 指向的问题
2. 普通函数是用arguments保存实际参数,箭头函数rest参数保存的实际参数
3.
es7新增属性
指数函数
格式 :输出几次幂
2**3 :输出2的三次幂
includes
includes(NaN) 能查找NaN
变量
ES5 var
特点 变量提升 可以重复声明,不具有块级作用域
let
特点: 不会变量提升,不可以重复声明,有块级作用域
const 常量声明
特点:不会变量提升,不可以重复声明,有块级作用域,
且是一个常量,在声明的时候就要被赋值,否则会报错。 不被更改值
解构
等号两侧的模式完全相同时才能完成解构
数组解构
完全解构
只有左右侧的数据类型相同,且模式完全相同时才能完成解构
例:
let [a,b,c,d,e] = [1,2,3,5] // 不是完全解构,因为元素的个数不一样
let [a,b,c,d] = [1,2,[3,4],5] // 则a=1,b=2,c=[3,4],d=5
不完全解构
不符合完全解构时,就是不完全解构
默认值解构
当右侧匹配严格模式为undefinded时 默认值才会生效,默认值则是在左边的默认等于值
例:
let [a=test()] = [], //a = test();
let [a=test()] = [1] //a=1;
集合解构 拓展运算符 …
即是三点运算符
let [a,...b] = [1,2,3,4,5] //a = 1,b =[2,3,4,5]
对象解构
属性名与变量名一致
注意!!要求属性名与变量名要一致
let {name,age} = {name:'zhangsan',age:12}
重命名解构
格式
let {name:a,age:b} = {name:'zhangsan',age:1] // name重命名为a,age重命名为b
嵌套解构
例:
let obj = {p:['hello',{y:'word'}]};
let {p:[a,{y:b}]} = obj // a=hello,b = word
字符串解构
利用数组来进行字符串解构
let [...arr] = 'hello' // arr = ['h','e','l','l','o']
利用对象解构字符串
拓展运算符 …
在拓展运算符中,用在左侧是聚合,用在右侧是展开
例:
let arr=[1,2,3]
let [...a] = arr; //a = [1,2,3];
let obj = {name:'zhangsan',age:12};
let obj1 = {gender:'man'};
let temp = [...obj,...obj1]; // temp={name:'zhangsan',age:12,gender:'man'};
函数参数
函数的长度只与其形参的个数有关,形参的个数是多少,长度就是多少,当函数的形参中有一个默认赋值,那么后面的所有形参的都默认为为参数,伪参数不计入长度
例:
function test(a,b,c){}
test.length === 3
test(a,b=2,c,d) ;
test.length===1
API
对象新增静态方法
is 比较两个数是否相等,返回true或者false
格式:
Object.is(+0,-0) //false
Object.is(NaN,NaN); //ture
assign
复制(两个参数),是半深拷贝
格式:
Object.assign(要复制成的目标对象,被复制的对象)
Object.assign(obj,obj1) // 把obj1的内容复制给obj, 并返回obj
注意,深拷贝的实现是被拷贝的对象中没有引用数据类型。如果没有引用数据类型实现的就是深拷贝,否则是浅拷贝。
合并对象(三个参数)
格式:
Object.assign(合并成的目标对象,要合并的对象1,要合并的对象2)
Object.assign(obj,obj1,obj2) //将obj1与obj2合并到obj ,并返回obj
获取原型对象的方法 .getPrototypeOf(obj)
设置原型对象方法 .setPrototype(obj,obj1)
Object.setPrototype(obj,obj1) //将obj的原型设置成obj1
keys 返回键组成的数组
默认对象是不能给for of 遍历的。
格式:Object.keys(obj),返回的是一个迭代器对象
values 返回的值组成的数组
返回的是一个迭代器对象
entries 返回键值对组成的数组
返回的是一个迭代器对象
fromEntries()用于把键值对还原成对象结构。
getPropertySymbols()获取symbol值
数组新增API
Array.prototype.find 返回第一个满足条件的元素或者undefined 参数回调函数
Array.prototype.find((item,index,arr)=>{}) find方法返回第一个满足条件的元素或者undefined 参数回调函数
let arr=[1,2,3,2,3];
let result=arr.find((item)=>{
return item>2
})
console.log(result) // 3
Array.prototype.findIndex() 返回第一个满足条件的元素的索引或者-1,参数是回调函数
例:
let arr=[1,2,3,2,3];
let result=arr.findIndex((item)=>{
return item>2
}) // 返回的是2
Array.prototype.includes(); includes是否包含某个元素,返回true/false
Array.prototype.fill() 用来填充数组,修改原数组
.flat(展开的层级数) 用于数组嵌套数组时展开数组
例:
[1, 2, [3, 4]].flat(); // [ 1, 2, 3, 4 ]
.flatMap()
是 .map() 与 .flat()的组合 ,通过对map调整后的数据尝试展平操作。
例:
[1, 2, [3, 4]].flatMap(v => {
if (typeof v === 'number') {
return v * 2
} else {
return v.map(v => v * 2)
}
})
// [2, 4, 6, 8]
String原型对象API
去除前后空格String.prototype.trimStart()/String.prototype.trimEnd()
格式:str.trimStart() //去除前空格
str.trimEnd() //去除后空格
头尾添加字符串String.prototype.padStart() / String.prototype.padEnd()
格式:str.padStart('要添加的字符串') //在头添加字符串
str.padEnd('要添加的字符串') //在尾添加字符串
Function.prototype.toString()
返回注释、空格和语法详细信息。
replaceAll 全部替换
类 class
注意在es6中没有原型的概念,类可以看成是构造函数的另一种写法,使用class关键字声明
类的声明
格式: constructor必须声明
class Person {
constructor(name) {
this.name = name
}
sayname(){}
static personAtrr = '静态属性'
static sayhi(){} //静态方法
}
constructor必须声明,里面写的是实例属性,如果没有显示声明,那么会初始化成一个空对象
方法sayname() 类似于存在原型中,每个实例都可以调用。
静态属性/方法,只能由类本身(例Person)的去调用,用static声明
在类体里面的引用数据类型是实例私有的,基本数据类型是公有的。
类的使用
格式:
let person =new Person('name')
继承
使用extends关键字进行继承
使用格式
class Animal{}
class dog extends Animal{
}
注意点
1.子类能调用父类的静态方法,
2.在继承中,先在子类的类体里面查找,再去父类的类体里面查找
3.子类能继承父类类体的所有方法
4.子类要继承父类的构造器的话,要提供constructor,且再里面使用super进行传递父类的constructor的参数,类似于借用父类的构造器
5.子类的对象通过__proto__指针指向父类的对象,子类的原型对象继承父类的原型对象
ES5与ES6的继承区别
ES5 :
子类原型对象继承父类的原型对象
Dog.prototype.__proto__ = Animal.prototype
子类继承父类
Dog.__proto__=Animal
symbol
是一个基本数据类型,表示一个独一无二的值,
作用
1.解决命名冲突
2.消除魔术字符串,即在多模块多次被重复使用相同的字符串
魔术字符串
消除魔术字符串,即在多模块多次被重复使用相同的字符串。
即在某一个模块中,这个字符串被修改之后,另外一个模块的对应字符串也要被修改才能正常使用,那么该字符串就是一个魔术字符串。
为解决这个问题可以使用symbol变量,为这个变量使用描述,即可便于以后的维护
使用格式
普通声明
let sy1=Symbol('hello'); // hello为该变量的描述,即使描述是一样的,二者的值不相同
let sy2=Symbol();
类似是key与value的关系
在对象里面使用
et obj={
name:"zhangsan",
age:12,
[sy1]:'myname',
[sy2]:'myage',
[Symbol('email')]:'kangjie@briup.com'
全局注册
当创建一个symbol变量时,使用该Symbol.for() 注册方法,可以使每次声明的变量时,就从全局注册表中查找该值,而不是重新创建一个值
使用格式
// 将symbol放到全局注册表中
let sy1=Symbol.for('hello');
// 从全局注册表中找到该key对应的value
let sy2=Symbol.for('hello');
keyFor() 检查给定的 key 是否已经在注册表中 ,
假如是,则会直接返回上次存储的那个。否则,它会再新建一个。
格式:
let sy1=Symbol.for('hello');
Symbol.keyFor(sy1) //hello
特点
1.forin循环访问不到我们的symbol值
2.获取symbol值要使用getPropertySymbols
3.当symbol值作为对象的属性名时,使用中括号 例:[sy3]:"myname"
迭代器 (Iterator)
迭代器是一种机制,一种接口,实现这种接口,就能使用for of 循环遍历
当数组调用keys() , values() , entries() 方法时,返回的是一个迭代器对象
当实现了迭代器接口后,才能使用for of循环进行遍历
for of遍历
与for in 的遍历不同的是,例字符串遍历中 for of 拿到的是一个对象值,而for in 是一个下标
实际原理
本质上调用迭代器对象的是next() 方法,把迭代器对象理解成一个指针,每调用一个next() 方法,得到的是一个解构的第一个成员,一直循环往复,直至所有解构的成员循环完毕
迭代器的 next() 指针
next指针存储着两个值 value盒done,value指向解构成员的值,done为false时表示不是最后一个成员,为true时表示时最后一个成员
keys ,values , entries 方法
当数组直接使用以上三种方法时,返回的是一个迭代器对象,把调用该方法返回值用来调用for of 才能实现真正的遍历。
例如 :第一次调用 .key.next() 得到的是一个下标成员
迭代器对象
实现某种迭代器接口的数据结构,只要实现了迭代器接口,那么就可以使用for of 方法
迭代器对象要遍历才能出我们想要的值
迭代器的作用
一是为各种数据结构,提供一个统一的、简便的访问接口;
二是使得数据结构的成员能够按某种次序排列;
三是ES6创造了一种新的遍历命令for...of循环,Iterator接口主要供for...of消费。
set 集合
类似一个数组,但成员的值是唯一的,没有重复的值。但引用数据类型可以重复,因为引用数据类型的地址不一样
set API
声明
var set = new Set()
添加成员 set.add(‘要添加的值’)
长度 set.size
删除 set.delete(‘要删除的值’)
注意,删除的时候引用数据类型要使用地址进行删除,否则无法删除引用数据类型
例:
temp = [1];
set.delete(temp)
遍历 set.forEach(),keys(),values(),entries()
清空全部set成员 set.clear()
作用
1.数组去重
2.存储值,因为成员是唯一的,不会重复的
map
类似一个对象,也是键值对的集合 ,但‘键’ 的范围不仅限于字符串,可以是各种类型的值
表现形式
{‘name’=> 'lisi' , 'age'=>12 }
map API
删除 map.delete(‘键值’)
注意,删除的时候引用数据类型要使用地址进行删除,否则无法删除引用数据类型
例:
temp = [1];
set.delete(temp)
map于obj的区别
Map | Object | |
---|---|---|
意外的键 | Map 默认情况不包含任何键。只包含显式插入的键。 | 一个 Object 有一个原型, 原型链上的键名有可能和你自己在对象上的设置的键名产生冲突。 |
键的类型 | 一个 Map的键可以是任意值,包括函数、对象或任意基本类型。 | 一个Object 的键必须是一个 String 或是Symbol。 |
键的顺序 | Map 中的 key 是有序的。因此,当迭代的时候,一个 Map 对象以插入的顺序返回键值。 | 一个 Object 的键是无序的。注意:自ECMAScript 2015规范以来,对象确实保留了字符串和Symbol键的创建顺序; 因此,在只有字符串键的对象上进行迭代将按插入顺序产生键。 |
Size | Map 的键值对个数可以轻易地通过size 属性获取 | Object 的键值对个数只能手动计算 |
迭代 | Map 是 iterable 的,所以可以直接被迭代。 | 迭代一个Object需要以某种方式获取它的键然后才能迭代。 |
性能 | 在频繁增删键值对的场景下表现更好。 | 在频繁添加和删除键值对的场景下未作出优化。 |
作用
1. 存储值,存储键值对形式的值,map比对象更合适,键可以是任意类型
async 异步函数
使用async声明的函数, 与await配合使用,await强制等待的,两种结合,
让我们可以用一种更简洁的方式写出基于Promise的异步行为,而无需刻意地链式调用promise。
即:内部封装了generator函数,是一个语法糖,内部自带执行器,与await配合使用;异步编程,同步处理;
作用
一般用于请求的发送,
try catch 异常捕获
当请求错误时,仅报了promise错误,对于错误的类型并未做出声明,那么解决这个问题可以使用trycatch里面来写异步请求,
当请求失败的时候就会走catch,也可以使用throw('失败')来抛出异常
否则走try,最后无论成功与否都会执行finally函数
同步与异步
同步
同一时间内,只能做一件事情,
在单线程中,按照代码的解析顺序从上到下执行同步代码
异步
在进入到事件循环的时,主要处理一个宏任务,
但是处理宏任务时遇到微任务时,会优先执行微任务
微任务
promise async
generator函数
异步编程的解决方案,他会返回一个迭代器的对象,真正的执行就是调用next()指针,会执行yiled状态。
一个yiled状态就是一个yiled代码节点
特点
1. function 和函数名之间必须有*号
例: function * test(){}
2. 内部使用yiled表达式,不使用return,最后一个可以使用return
yield
一个yiled状态就是一个yiled代码节点,即一个yield就是一个节点。
Generator函数内部使用的是yield,不使用return
例:
function * Generator(){
// 内部使用的是yield表达式
yield '1';
yield '2'
yield '3'
}
当调用Generator函数时,第一次调用即调用next()会返回 yield的第一个状态,即'1',第二次执行会得到 '2' ,
状态参数之间的传递
注意第一个状态的执行在代码里面就算使用了参数接收,也不会被那个参数所拿到,所以后续的状态如果需要使用上一状态的结果,就会拿不到。
即
function * Generator(){
// 内部使用的是yield表达式
let res = yield '1'; //注意res是拿不到 1 的
yield '2'
yield '3'
}
所以我们要把第一个状态传递到第二个状态里,那么在第一个异步请求里面调用第二个状态
例子:
function *Generator(){
let res=yield getData();
console.log(res);
// 上一个状态声明变量 下一个状态使用
yield '结束了';
}
let res=Generator();
res.next()
async function getData(){
let response=await axios.get('http://121.199.0.35:8888/index/article/findCategoryArticles');
// 如果想要实现数据传递 需要发起第二段程序执行
// 拿上一个状态得返回值作为下一个状态得入口
res.next(response.data)
}
promise
是一个承诺对象,存放着将来才会执行的代码。不是一个同步代码,同步代码是立即执行的代码。
promise 是解决异步编程的方案。
作用
1.使用promise封装ajax,注意不是axios
2.异步操作,同步解决,避免了层层嵌套的回调函数,可以链式调用降低了操作难度
使用
声明promise对象
格式:
let promise = new Promise((resolve,reject)=>{
})
promise 参数
new Promise(resolve,reject);二者是一个回调函数
resolve: 成功的回调函数
reject: 失败的回调函数
promise 的实例方法
格式:
promise.then((res){}).catch((err)=>{}).finally(()=>{}) --->链式调用,每次链式调用返回的都是一个promise实例,所以能链式调用
then
resolve 函数就由then提供,执行请求成功的回调函数,可以放两个参数。
例:
promise.then((res)=>{},(err)=>{}) -->第一个参数是请求成功的回调,第二个参数是请求失败的回调
catch
reject 方法由catch提供,执行失败的回调函数
finally
无论成功或者失败都会执行的回调函数,一般会应用于loading。
promise 的状态status
fulfilled
请求成功
rejected
请求失败
pedding
等待/进行中
promise封装ajax
function promise(method,url){
return new Promise((resolve,reject)=>{
let xhr = new XMLHttpRequest();
xhr.open(method,url);
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readyState===4){
if(xhr.status===200){
reslove(xhr.responseText)
}else{
reject(xhr.responseText)
}
}
}
})
}
// 使用
let p1 = promise('get','url');
p1.then(res =>{})
静态方法 Promise
Promise.all()
实例请求全部成功后返回一个承诺对象,
参数:
Promise.all([存放多个promise实例对象])
例:Promise.all([p1,p2])
返回值:
返回一个promise实例 ,当全部实例请求成功后才能返回一个成功的状态码,里面存放了一个数组,数组里面存放了每个请求实例返回的对象
Promise.any()
返回一个承诺对象,实例全部失败则返回一个失败状态码,有成功的实例则返回一个成功的状态码,value存放一个请求成功的全部数据
Promise.race()
赛跑返回先请求成功的实例,
Promise.allSettled()
把请求的实例对象 封装成 Arry[ {里面是一个实例请求} {} ],
把实例的请求都放在数组里面,不管是请求失败还是成功。
事件循环
同步代码>微任务>宏任务,
事件循环主要用于执行宏任务
一次事件循环,只能处理一次宏任务。执行完一个宏任务之后会进行一个轮询,检查是否有微任务,有微任务会把所有微任务执行完毕,之后执行宏任务。
同步代码为立即执行的代码,主要是从上到下的优先级,当同步任务遇到异步任务,异步任务不会立即执行,把异步任务放到任务队列中,继续向下执行同步任务
微任务
await后面的代码属于微任务,与promise.then同级别,
promise.then>promise.finally 二者都是微任务。但不在then或finally里面的任务是同步任务
宏任务
setTimeout setInterval ajax Dom事件
微任务
promise.then/finalli async/await(注意,执行await时后面的代码会隐式在外层嵌套promise.then,变成微任务)
// 事件循环
setTimeout(function () { // 宏任务
console.log('1');
});
async function test(){
console.log('5') // 同步代码,立即执行
await async2(); // 微任务 ----》
//相当于 new Promise(()=>{
// async2()
//}).then(()=>{}).finally(()=>{ console.log('6')})
console.log('6') // 微任务
}
new Promise(function (resolve) {
console.log('2'); // 同步代码,立即执行
resolve();
}).then(function () { // 微任务
console.log('3');
}).finally(()=>{ // 微任务
console.log('8');
})
function async2(){
console.log('7'); // 同步代码
}
test()
console.log('4');
2 5 7 4 3 6 8 1