前端-ES6-11
1. ES介绍
ES全称ECMAScript,是脚本语言的规范。而平常我们编写的JavaScript,是ECMAScript的一种实现,所以ES新特性其实指的就是JavaScript的新特性。
为什么学习新特性?
- 语法简洁,功能丰富
- 框架开发应用
- 前端开发职位要求
2. ES6入门
① let
let变量声明及声明特性
声明方式:
let alet b,c,dlet e=100let f=521,g='iloveyou',h=[]
声明特性:
- ① 变量不能重复声明(var可以重复声明)
- ② 块级作用域(全局、函数、eval)
{let girl='高圆圆'}console.log(girl) //Uncaught ReferenceError: girl is not defined
- ③ 不存在变量提升
console.log(song) //Uncaught ReferenceError: Cannot access 'song' before initializationlet song='恋爱达人'
- ④ 不影响作用域链
{let school='尚硅谷'function fn(){console.log(school) //尚硅谷}fn()}
let经典案例
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><style>.item{width:100px;height:50px;border:1px solid #799;float:left;margin:0 20px;}</style>
</head>
<body><div class="container"><h2 class="page-header">点击切换颜色</h2><div class="item"></div><div class="item"></div><div class="item"></div></div>
<script>let items=document.getElementsByClassName('item')for(let i=0;i<items.length;i++){items[i].onclick=function(){console.log(i)items[i].style.background='pink'}}
</script>
</body>
</html>
let与var声明变量比较:
特点 | let | var | 备注 |
作用域 | 代码块内 | 全局范围内 | for循环计数器很适合用let |
重复声明 | 不可以 | 可以 | |
变量提升 | 不存在 | 存在 |
② const
const 声明常量及特点
声明常量方式:
const SCHOOL='尚硅谷'
声明特点:
- ① 一定要赋初值
const A //Uncaught SyntaxError: Missing initializer in const declaration
- ② 一般常量使用大写(潜规则)
- ③ 常量的值不能修改
const SCHOOL='尚硅谷'SCHOOL='黑马程序员' //Uncaught TypeError: Assignment to constant variable.
- ④ 块级作用域
{const PLAYER='UZI'}console.log(PLAYER) //Uncaught ReferenceError: PLAYER is not defined
- ⑤ 对于数组和对象元素的修改,不算做对常量的修改,不会报错
const TEAM=['UZI','MXLG','MING','Letme']TEAM.push('Meiko') //不会报错
let
、const
和 var
比较:
特性 | var | let | const |
---|---|---|---|
作用域 | 函数作用域 | 块级作用域({} 内有效) | 块级作用域({} 内有效) |
变量提升 | 是(声明提升,值为 undefined ) | 是(TDZ 暂时性死区,未初始化前不可访问) | 是(TDZ 暂时性死区,未初始化前不可访问) |
重复声明 | 允许 | 禁止(同一作用域内) | 禁止(同一作用域内) |
初始值要求 | 可选 | 可选 | 必须初始化(声明时赋值) |
修改值 | 允许 | 允许 | 基本类型不可改,引用类型可修改属性 |
全局声明时的行为 | 成为全局对象的属性(如 window.varName ) | 不在全局对象上定义(window.letName 为 undefined ) | 同 let |
典型用途 | 旧代码兼容 | 需要重新赋值的变量 | 常量或不需要重新赋值的引用类型 |
③ 变量的解构赋值
ES6允许按照一定模式从数组和对象中提取值,对变量进行赋值,这被称为解构赋值
1.数组的解构
- 数组的结构采用数组字面量的语法形式
- 等号左边的变量通过在数组中的位置去取得等号右边的数组字面量相同位置的值
const F4=['小沈阳','刘能','赵四','宋小宝']let [xiao,liu,zhao,song]=F4console.log(xiao) //小沈阳console.log(liu) //刘能console.log(zhao) //赵四console.log(song) //宋小宝
2.对象的解构
- 写法:{变量1,变量2,……,变量n}=对象
- 注意:对象解构是按照属性名解构的,不管顺序。即属性名和变量名则相同解构
const zhao={name:'赵本山',age:'不详',xiaopin:function(){console.log('我可以演小品')}}let {name,age,xiaopin}=zhaoconsole.log(name) //赵本山console.log(age) //不详console.log(xiaopin) //function(){ console.log('我可以演小品') }xiaopin() //我可以演小品
④ 模板字符串
1.声明
let str=`我也是一个字符串哦`console.log(str,typeof str) //我也是一个字符串哦 string
2.内容中可以直接出现换行符(单引号和双引号不能)
let str=`
<ul><li>沈腾</li><li>马丽</li><li>魏晨</li><li>艾伦</li>
</ul>`console.log(str)/**运行结果:<ul><li>沈腾</li><li>马丽</li><li>魏晨</li><li>艾伦</li></ul>* */
3.变量拼接
其中变量需要通过固定的形式 ${变量名} 进行拼接
let lovest='魏晨'let out=`${lovest}是我心中最搞笑的演员`console.log(out) //魏晨是我心中最搞笑的演员
⑤ 对象简化写法
ES6允许在大括号里面,直接写入变量和函数,作为对象的属性和方法
let name='尚硅谷'let change=function(){console.log('我们可以改变你')}const school={name,change}/**等效的写法是:* const school={* name:name,* change:change* }* */
对象中的方法可以简化掉 :function 关键字
const school={improve(){console.log('我们可以提高你的技能')}}/*等价的写法是:const school={improve:function(){console.log('我们可以提高你的技能')}}*/
⑥ 箭头函数
以及其声明特点,ES6允许使用箭头(=>)定义函数
let fn=(name,age)=>{console.log(`我的名字是:${name},
我的年龄是:${age}`)}fn('林俊杰',34)/**运行结果:*我的名字是:林俊杰,*我的年龄是:34* */
箭头函数特性:
- 1. this是静态的,this始终指向函数声明时所在作用域下的this的值
function getName(){console.log(this.name)}let getName2=()=>{console.log(this.name)}window.name='尚硅谷'const school={name:'atguigu'}getName() //尚硅谷getName2() //尚硅谷getName.call(school) //atguigugetName2.call(school) //尚硅谷
- 2.不能作为构造函数实例化对象
let Person=(name,age)=>{this.name=namethis.age=age}let p1=new Person('林俊杰','34') //Uncaught TypeError: Person is not a constructor
- 3.不能使用arguments变量
let fn=()=>{console.log(arguments)}fn(1,2,3) //Uncaught ReferenceError: arguments is not defined
- 4.箭头函数的简写
1)当形参有且只有一个时,可以省略小括号
let add=n=>{console.log(n+n)}add(9) //18
2)当代码体只有一条语句时,可以省略花括号
let mul=n=>console.log(n*n)mul(5) //25
省略花括号时,return也必须省略,而且此时语句的执行结果就是函数的返回值
let add=n=>n+nconsole.log(add(6)) //12
箭头函数的实践与应用
箭头函数适合与this无关的回调、定时器、数组方法的回调
箭头函数不适合与this有关的回调、事件回调、对象的方法
/*需求:*点击#ad 2s后颜色变为粉色* */let ad=document.getElementById('ad')ad.onclick=function(){setTimeout(()=>{this.style.background='pink'},2000)}/**需求:* 从数组中返回偶数的元素* */const arr=[1,6,9,10,100,25]const result=arr.filter(item=>item%2===0)console.log(result)
⑦ 函数参数的默认值设置
ES6允许给函数参数赋初始值
- 1.形参初始值 具有默认值的参数,一般位置要靠后(潜规则)
function add(a,b=5,c=10){return a+b+c}let result=add(1,2)console.log(result) //13
- 2.与解构赋值结合
function connect({host='localhost',username,password,port}){console.log(host,username,password,port)
}
connect({host:'atguigu',username:'root',password:'123321',port:5500
}) //atguigu root 123321 5500
⑧ rest参数
ES6引入rest参数,用于获取函数的实参,用来代替arguments
function connect({host='localhost',username,password,port}){console.log(host,username,password,port)
}
connect({host:'atguigu',username:'root',password:'123321',port:5500
}) //atguigu root 123321 5500
rest参数必须放在最后
function date(a,b,c,...args){console.log(a,b,c)console.log(args)}date(1,2,3,'阿Sa','柏芝','思慧')/**运行结果:* 1 2 3* Array(3) ["阿Sa", "柏芝", "思慧"]* */
⑨ 扩展运算符
...为扩展运算符,能将数组转换为逗号分隔的参数序列
function date(a,b,c,...args){console.log(a,b,c)console.log(args)}date(1,2,3,'阿Sa','柏芝','思慧')/**运行结果:* 1 2 3* Array(3) ["阿Sa", "柏芝", "思慧"]* */
扩展运算符的应用:
1.数组的合并
//1.数组的合并const kuaizi=['王太利','肖央']const fenghuang=['曾毅','玲花']const zxmzq=[...kuaizi,...fenghuang]console.log(zxmzq) //Array(4) ["王太利", "肖央", "曾毅", "玲花"]
2.数组的克隆
const sanzhihua=['E','G','M']
const clone=[...sanzhihua]
console.log(clone) //Array(3) ["E", "G", "M"]
3.将伪数组转换为真正的数组
const divs=document.querySelectorAll('div')console.log(divs) //NodeList(3) [div, div, div]const divArr=[...divs]console.log(divArr) //Array(3) [div, div, div]
3. Symbol
ES6引入了一种新的原始数据类型Symbol,表示独一无二的值
它是JS的第七种数据类型,是一种类似于字符串的数据类型。
① Symbol的特点:
① Symbol的值是唯一的,用来解决命名冲突的问题。
② Symbol的值不能与其他数据类型进行运算。
③ Symbol定义的对象属性不能使用for...in循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有键名
//创建 Symbol// 方式一let s=Symbol()console.log(s,typeof s) //Symbol() symbol// 方式二let s2=Symbol('尚硅谷')let s3=Symbol('尚硅谷')console.log(s2===s3) //false// 方式三let s4=Symbol.for('尚硅谷')console.log(s4,typeof s4) // Symbol(尚硅谷) symbollet s5=Symbol.for('尚硅谷')console.log(s4===s5) //true
② 对象添加Symbol类型的属性
方式一:
// 向对象中添加方法 up downlet game={}// 声明一个对象let methods={up:Symbol(),down:Symbol()}game[methods.up]=function(){console.log('我可以改变形状')}game[methods.down]=function(){console.log('我可以快速下降')}console.log(game)
方式二:
let game={name:'狼人杀',[Symbol('say')]:function(){console.log('我可以发言')},[Symbol('zibao')]:function(){console.log('我可以自爆')}}console.log(game)
③ Symbol内置值
除了定义自己使用的Symbol值以外,ES6还提供了11个内置的Symbol值,指向语言内部使用的方法
类型检测:Symbol.hasInstance
当其他对象使用instanceof运算符,判断是否为该对象的实例时,会调用这个方法
class Person{static [Symbol.hasInstance](param){console.log(o)console.log('我被用来检测类型了')}}let o={}console.log(o instanceof Person)
Symbol.isConcatSpreadable
对象的Symbol.isConcatSpreadable属性等于的是一个布尔值,表示该对象用于Array.prototype.concat()时,是否可以展开
const arr=[1,2,3]const arr2=[4,5,6]console.log(arr.concat(arr2)) //Array(6) [1, 2, 3, 4, 5, 6]arr2[Symbol.isConcatSpreadable]=falseconsole.log(arr.concat(arr2)) //Array(4) [1, 2, 3, Array(3)]
④ JS中的数据类型
类型 | 分类 | 特性说明 | 示例 |
---|---|---|---|
Number | 原始类型 | 数值(整数、浮点数、Infinity 、NaN ) | 42 , 3.14 , NaN |
String | 原始类型 | 字符串(单/双引号或模板字符串) | 'hi' , "hello" , `world` |
Boolean | 原始类型 | 逻辑值(true /false ) | true , false |
Undefined | 原始类型 | 变量未初始化时的默认值 | let a; (a 为 undefined ) |
Null | 原始类型 | 显式赋值的空值(typeof null 返回 "object" ,这是历史遗留问题) | let b = null; |
Symbol | 原始类型 | 唯一且不可变的值(ES6 新增,用于对象属性键) | Symbol('id') |
BigInt | 原始类型 | 大整数(ES2020 新增,表示任意精度整数) | 123n , 9007199254740991n |
Object | 引用类型 | 复合数据类型(包含普通对象、数组、函数、日期等) | {name: 'Alice'} , [1, 2] , function() {} |
4. 迭代器
① 迭代器介绍
迭代器(Iterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署Iterator接口(就是一个属性),就可以完成遍历操作
- 1. ES6创造了一种新的遍历命令for...of循环,Iterator接口主要供for...of消费
- 2. 原生具备iterator接口的数据(可用for of遍历)
- 1)Array
- 2)Arguments
- 3)Set
- 4)Map
- 5)String
- 6)TypedArray
- 7)NodeList
- 3. 工作原理
创建一个指针对象,指向当前数据结构的起始位置
第一次调用对象的next方法,指针自动指向数据结构的第一个成员
接下来不断调用next方法,指针一直往后移动,直到指向最后一个成员
每调用next方法返回一个包含value和done属性的对象
注:需要自定义遍历数据的时候,要想到迭代器
// 声明一个数组const west=['唐僧','孙悟空','猪八戒','沙僧']// 使用 for...of 遍历数组for(let v of west){console.log(v)}console.log(west)let iterator=west[Symbol.iterator]()console.log(iterator.next())console.log(iterator.next())console.log(iterator.next())console.log(iterator.next())console.log(iterator.next())
② 自定义遍历数据
const class1={name:'终极一班',stus:['xiaoming','xiaoning','xiaotian','knight'],[Symbol.iterator](){let index=0return {next:()=>{if(index<this.stus.length){const result={value:this.stus[index],done:false}index++return result}else{return {value:undefined,done:true}}}}}}for(let v of class1){console.log(v)}
③ 生成器函数的声明和调用
生成器其实就是一个特殊的函数
异步编程 纯回调函数 node fs ajax mongodb
function *gen(){console.log("hello generator")}let iterator=gen()console.log(iterator) //gen {[[GeneratorState]]: "suspended"}iterator.next() //hello generator
yield可以看做函数代码的分隔符,
用来暂停和恢复一个生成器函数(function*
)
function *gen(){console.log(111)yield '一直没有耳朵';console.log(222)yield '一直没有尾巴';console.log(333)yield '真奇怪'console.log(444)}let iterator=gen()iterator.next()iterator.next()iterator.next()iterator.next()iterator.next()for(let v of gen()){console.log(v)}
④ 生成器函数的参数传递
在next函数中传递的参数会作为上一次调用next函数的返回值
function *gen(arg){console.log(arg)let one=yield 111;console.log(one)let two=yield 222;console.log(two)let three=yield 333;console.log(three)}let iterator=gen('AAA')console.log(iterator.next())console.log(iterator.next('BBB'))console.log(iterator.next('CCC'))console.log(iterator.next('DDD'))
⑤ 生成器函数实例
let one=()=>{setTimeout(()=>{console.log(111)iterator.next()},1000)}let two=()=>{setTimeout(()=>{console.log(222)iterator.next()},1000)}let three=()=>{setTimeout(()=>{console.log(333)iterator.next()},1000)}function* gen(){yield one();yield two();yield three();}const iterator=gen()iterator.next()
let getUsers=()=>{setTimeout(()=>{let data='用户数据'iterator.next(data)},1000)}let getOrders=()=>{setTimeout(()=>{let data='订单数据'iterator.next(data)},2000)}let getGoods=()=>{setTimeout(()=>{let data='商品数据'iterator.next(data)},3000)}function* gene(){let users=yield getUsers();console.log(users)let orders=yield getOrders();console.log(orders)let goods=yield getGoods();console.log(goods)}let iterator=gene()iterator.next()
5. Promise
① 简介
Promise是ES6引入的异步编程的新解决方案。语法上Promise是一个构造函数,用来封装一步操作并可以获取其成功或失败的结果
- 1)Promise构造函数:Promise(executor){}
- 2)Promise.prototype.then方法
- 3)Promise.prototype.catch方法
实例化promise时传入一个函数,有两个参数:resolve和reject
调用resolve封装数据则代表成功,调用reject封装数据则代表失败
实例化promise对象的then方法,可以传入两个函数,第一个对应resolve封装的数据,参数是value;第二个对应reject封装的数据,参数是reason
//实例化 Promiseconst p=new Promise(function (resolve, reject){setTimeout(function(){let err='数据读取失败'reject(err)},1000)})//调用promise对象的then方法p.then(function(value){console.log(value)},function(reason){console.log(reason)})
② 封装读取文件
//1.引入fs模块
const fs=require('fs')//2.使用promise封装
const p=new Promise(function(resolve,reject){fs.readFile('./study.txt',(err,data)=>{if(err) reject(err)resolve(data)})
})p.then(function(value){console.log(value.toString())
},function(reason){console.log('读取失败')
})
③ 封装Ajax操作
原生ajax:
//1.创建对象const xhr=new XMLHttpRequest()//2.初始化xhr.open('GET','http://localhost:8080/getJoke')//3.发送xhr.send()//4.绑定事件,处理响应结果xhr.onreadystatechange=function(){if(xhr.readyState===4){if(xhr.status>=200&&xhr.status<300){console.log(xhr.response)}else{console.error(xhr.status)}}}
promise封装:
const p=new Promise(function(resolve, reject){const xhr=new XMLHttpRequest()xhr.open('GET','http://localhost:8080/getJoke')xhr.send()xhr.onreadystatechange=function(){if(xhr.readyState===4){if(xhr.status>=200&&xhr.status<300){resolve(xhr.response)}else{reject(xhr.status)}}}})p.then(function(value){console.log(value)},function(reason){console.log(reason)})
④ then方法
then方法的返回结果是Promise对象,该对象状态由回调函数的执行结果决定
1.如果回调函数中返回的结果是非promise类型的属性,状态为成功,且返回值为对象的成功值(PromiseStatus:fulfilled)
2.如果返回的结果是promise对象,则返回值为该对象
3.抛出错误,PromiseResult即为抛出的错误
//创建promise对象const p=new Promise((resolve,reject)=>{setTimeout(()=>{resolve('成功了')// reject('出错了')},1000)})//调用then方法const result=p.then(value=>{console.log(value)// return 123// return new Promise((resolve,reject)=>{// reject('not ok')// })throw new Error('出错了')},reason=>{console.log(reason)})console.log(result)
链式调用
p.then(value=>{},reason=>{}).then(value=>{},reason=>{})
⑤ 示例
多个文件内容读取
回调地狱版:
const fs=require('fs')fs.readFile('./study.txt',(err,data1)=>{fs.readFile('./插秧诗.txt',(err,data2)=>{fs.readFile('./观书有感.txt',(err,data3)=>{let result=`${data1}
${data2}
${data3}`console.log(result)})})
})
Promise版:
const fs=require('fs')const p=new Promise((resolve,reject)=>{fs.readFile('./study.txt',(err,data)=>{resolve(data)})
})p.then(value=>{return new Promise((resolve,reject)=>{fs.readFile('./插秧诗.txt',(err,data)=>{resolve([value,data].join('\r\n'))})})
}).then(value=>{return new Promise((resolve,reject)=>{fs.readFile('./观书有感.txt',(err,data)=>{resolve([value,data].join('\r\n'))})})
}).then(value=>{console.log(value)
})
⑥ catch方法
用来指定promise失败的回调
const p=new Promise((resolve,reject)=>{setTimeout(()=>{//设置p对象的状态为失败,并设置失败的值reject('出错了')},1000)
})
p.catch(reason=>{console.log(reason)
})
6. 集合与API
① Set
ES6提供了新的数据结构Set(集合)。它类似于数组,但成员的值都是唯一的,集合实现了iterator接口,所以可以使用扩展运算符和for…of……进行遍历
集合的属性和方法:
1)size 返回集合的元素个数
2)add 增加一个新元素,返回当前集合
3)delete 删除元素,返回boolean值
4)has 检测集合中是否包含某个元素,返回boolean值
//声明一个set
let s=new Set()
let s2=new Set([1,2,3,4,5,6])// 元素个数
console.log(s2.size)
// 添加新的元素
s2.add(9)
// 删除元素
s2.delete(5)
// 检测
console.log(s2.has(4))
// 遍历
for(let v of s2){console.log(v)
}
// 清空
s2.clear()
② 集合实践
let arr=[1,2,3,4,5,4,3,2,1]
// 1.数组去重
let result=[...new Set(arr)]
// 2.交集
let arr2=[4,5,6,5,4]
let r2=[...new Set(arr)].filter(item=>{let s2=new Set(arr2)return s2.has(item)
})
// 3.并集
let union=[...new Set([...arr,...arr2])]
// 4.差集
let diff=[...new Set(arr)].filter(item=>!new Set(arr2).has(item)
)
③ Map
ES6提供了Map数据结构。它类似于对象,也是键值对的集合。但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当键。Map也实现了iterator接口,所以可以使用扩展运算符和for...of...进行遍历
Map的属性和方法:
- 1)size 返回Map的元素个数
- 2)set 增加一个新元素,返回当前Map
- 3)get 返回键名对象的键值
- 4)has 检测Map中是否包含某个元素,返回boolean值
- 5)clear 清空集合,返回undefined
- 6)delete 根据键删除键值对
// 声明Map
let m=new Map()// 添加元素
m.set('name','尚硅谷')
m.set('change',function(){console.log('我们可以改变你')
})
let key={school:'ATGUIGU'
}
m.set(key,['北京','上海','深圳'])
//size
console.log(m.size)
//删除
m.delete('name')
//获取
console.log(m.get('change'))
//遍历
for(let v of m){console.log(v)
}
7. Class
① 简介
ES6提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板。
通过class关键字,可以定义类。基本上,ES6的class可以看做只是一个语法糖,它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已
知识点:
- 1)class声明类
- 2)constructor定义构造函数初始化
- 3)extends继承父类
- 4)super调用父级构造方法
- 5)static定义静态方法和属性
- 6)父类方法可以重写
ES5写法:
function Phone(brand,price){this.brand=brandthis.price=price
}
Phone.prototype.call=function(){console.log('我可以打电话')
}
let Huawei=new Phone('华为',6988)
Huawei.call()
console.log(Huawei)
ES6写法:
class Phone{// 构造方法,名字不能修改constructor(brand,price) {this.brand=brandthis.price=price}// 方法必须使用该语法,不能使用ES5的对象完整形式call(){console.log('我真的可以打电话')}
}
let onePlus=new Phone('1+',1900)
console.log(onePlus)
onePlus.call()
② class静态成员
function Phone(){}
Phone.name='手机'
Phone.change=function(){console.log('我可以改变世界')
}
let nokia=new Phone()
console.log(nokia.name)
nokia.change()
实例对象和函数对象的属性不互通
实例对象的属性和构造函数的原型对象相通
把属于类而不属于实例对象的属性称为静态成员
即,对于static标注的属性,属于类而并不属于对象
class Phone{static name ='手机'static change(){console.log('我可以改变世界')}
}
let nokia=new Phone()
console.log(nokia.name)
console.log(Phone.name)
③ ES5使用构造函数实现继承
function Phone(brand,price){this.brand=brandthis.price=price
}
Phone.prototype.call=function(){console.log('我可以打电话')
}
function SmartPhone(brand,price,color,size){Phone.call(this,brand,price)this.color=colorthis.size=size
}
// 设置子级构造函数的原型
SmartPhone.prototype=new Phone
SmartPhone.prototype.constructor=SmartPhone// 声明子类的方法
SmartPhone.prototype.photo=function(){console.log('我可以拍照')
}
SmartPhone.prototype.playGame=function(){console.log('我可以玩游戏')
}
const cz=new SmartPhone('锤子',2499,'黑色','5.5inch')
console.log(cz)
④ class类继承
class Phone{constructor(brand,price) {this.brand=brandthis.price=price}call(){console.log('我可以打电话')}
}class SmartPhone extends Phone{constructor(brand,price,color,size) {super(brand,price);this.color=colorthis.size=size}photo(){console.log('拍照')}playGame(){console.log('玩游戏')}
}
const xm=new SmartPhone('小米',7799,'red','5.5inch')
console.log(xm)
xm.call()
xm.photo()
xm.playGame()
⑤ 子类对父类方法的重写
class SmartPhone extends Phone{constructor(brand,price,color,size) {super(brand,price);this.color=colorthis.size=size}photo(){console.log('拍照')}playGame(){console.log('玩游戏')}call(){console.log('我可以进行视频通话')}
}
⑥ getter和setter的设置
class Phone{get price(){console.log('价格属性被读取了')return 'naomukiyo'}set price(newVal){console.log('价格属性被修改了:'+newVal)}
}
let s=new Phone()
console.log(s.price) //得到price的get方法返回值
s.price='free'
8. ES6扩展
① ES6的数值扩展
- 1. Number.EPSILON是JavaScript能表示的最小精度
function equal(a,b){if(Math.abs(a-b)<Number.EPSILON){return true}return false
}console.log(0.1+0.2===0.3) //false
console.log(equal(0.1+0.2,0.3)) //true
- 2. 二进制和八进制
let b=0b1010 //二进制
let o=0o777 //八进制
let d=100 //十进制
let x=0xff //十六进制
- 3. Number.isFinite 检测一个数值是否为有限数
console.log(Number.isFinite(100)) //trueconsole.log(Number.isFinite(100/0)) //falseconsole.log(Number.isFinite(Infinity)) //false
- 4. Number.isNaN 检测一个数值是否为NaN
console.log(Number.isNaN(123)) //falseconsole.log(Number.isNaN('abc')) //false
- 5. Number.parseInt 和 Number.parseFloat 字符串转整数
console.log(Number.parseInt('123px')) //123console.log(Number.parseFloat('3.141589m')) //3.14159
- 6. Number.isInteger 判断一个数是否为整数
console.log(Number.isInteger('123')) //falseconsole.log(Number.isInteger(23)) //true
- 7. Math.trunc 将数字的小数部分抹掉
console.log(Math.trunc(4.67)) //4
- 8. Math.sign 判断一个数到底是正数、负数还是零
console.log(Math.sign(100)) //1console.log(Math.sign(0)) //0console.log(Math.sign(-100)) //-1
② 对象方法的扩展
- 1. Object.is 判断两个值是否完全相等 类似于完全等于===
console.log(Object.is({name:"尚硅谷"},{name:"尚硅谷"})) //false
- 2. Object.assign 对象的合并
该方法传递两个参数,如果属性值一样,后面的会将前面的相同属性的属性值覆盖
const config1={host:'localhost',port:3306,name:'root',password:'root'
}
const config2={host:'http://atguigu.com',port:33060
}
console.log(Object.assign(config1,config2))
/*
*运行结果:
*host = "http://atguigu.com"
*port = 33060
*name = "root"
*password = "root"
*
* */
- 3. Object.setPrototypeOf 设置原型对象
const school={name:'尚硅谷'
}
const cities={xiaoqu:['北京','上海','深圳']
}
Object.setPrototypeOf(school,cities)
console.log(Object.getPrototypeOf(school)) //Object {xiaoqu: Array(3)}
console.log(school) //Object {name: "尚硅谷"}
9. 模块化
① 概述
模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来。
好处:
防止命名冲突
代码复用
高维护度
模块化规范的产品:
ES6之前的模块化规范有:
1)CommonJS => NodeJS、Browserify
2)AMD => requireJS
3)CMD => seaJS
② ES6模块化语法
模块功能主要由两个命令构成:export和import
export命令用于规定模块的对外接口
import命令用于输入其他模块提供的功能
0.分别暴露
export let school='尚硅谷'export function teach(){console.log('我们可以教给你开发技能')
}
<script type="module">import * as m1 from './index.js'm1.teach() //我们可以教给你开发技能console.log(m1.school) //尚硅谷
</script>
③ ES6模块暴露数据语法汇总
1.统一暴露
let school='尚硅谷'function findJob(){console.log('我们可以帮助你找工作')
}export {school,findJob}
<script type="module">import * as m2 from './index.js'
</script>
2.默认暴露
export default{school:'ATGUIGU',change(){console.log('我们可以改变你')}
}
<script type="module">import * as m3 from './index.js'console.log(m3.default.school) //ATGUIGUm3.default.change() //我们可以改变你
</script>
④ ES6引入模块数据语法汇总
1.通用的导入方式
import * as m3 from './index.js'
2.解构赋值的形式
<script type="module">import {school,teach} from './index.js'teach() //我可以教你技术
</script>
解构赋值中如果遇到属性值同名,可以使用as起别名
import {school,teach} from './index.js'import {school as guigu,findJob} from './m3.js'
当遇到使用default默认暴露,可以对default起别名
export default {school:'atguigu',change(){console.log('我们可以改变你')}
}
<script type="module">import {default as m3} from './index.js'm3.change()
</script>
3.简便形式 但只能针对默认暴露
<script type="module">import m3 from './index.js'm3.change()
</script>
⑤ 浏览器使用ES6模块化方式二
// 模块引入
import * as m1 from './m1.js'
import * as m2 from './m2.js'
import * as m3 from './m3.js'console.log(m1)
console.log(m2)
console.log(m3)
<script src="./app.js" type="module"></script>
⑥ babel对ES6模块化代码的转换
1.安装工具 babel-cli babel-preset-env browserify(实际项目中用webpack)
npm i babel-cli babel-preset-env browserify -D
2.如果是局部安装babel,则需要用npx进行转换
第一个参数:js文件原先所在目录
第二个参数:转换后的js文件所在目录
npx babel es6 -d dist --presets=babel-preset-env
3.打包 npx browserify dist/index.js -o dist/bundle.js
npx browserify dist/index.js -o dist/bundle.js
⑦ ES6模块化引入NPM包
1.安装jQuery
npm i jquery
2.导入jQuery包
import $ from 'jquery' //等价于 const $=require('jquery')
3.编写代码,修改背景颜色为粉色
$('body').css('background','pink')
4.重新打包
npx babel es6 -d dist --presets=babel-preset-env
npx browserify dist/app.js -o dist/bundle.js
5.html中引入对应的打包文件
<script src="../dist/bundle.js" type="module"></script>
10. ECMAScript7 新特性
① Array.prototype.includes : includes方法用阿里检测数组中是否包含某元素,返回布尔类型值
const mz=['西游记','红楼梦','三国演义','水浒传']console.log(mz.includes('西游记')) //trueconsole.log(mz.includes('金瓶梅')) //false
② 指数操作符: 在ES7中引入指数运算符**,用来实现幂运算,功能和Math.pow结果相同
console.log(2**10) //1024
11. ECMAScript8 新特性
① async和await
async和await两种语法结合可以让异步代码像同步代码一样
async函数:
async函数的返回值为promise对象
promise对象的结果由async函数执行的返回值决定
await表达式:
await必须写在async函数中
await右侧的表达式一般为promise对象
await返回的是promise成功的值
await的promise失败了,就会抛出异常,需要通过try...catch捕获处理
async:
1. async函数中,只要返回的结果不是一个Promise类型的对象,则该函数的返回值就是一个成功的Promise
async function fn(){return '尚硅谷'
}console.log(fn()) //Promise {[[PromiseState]]: "fulfilled", [[PromiseResult]]: "尚硅谷"}
2. 如果抛出错误,则返回的结果是一个失败的Promise
3. 返回的结果如果是一个Promise对象,则成功与否由这个Promise对象决定
await:
const p=new Promise((resolve, reject)=>{// resolve('用户数据')reject('失败了')})async function fn(){try{let result=await pconsole.log(result)}catch(e){console.log(e)}}
② async和await结合读取文件内容
const fs=require('fs')let read=(filePath)=>{return new Promise((resolve,reject)=>{fs.readFile(filePath,(err,data)=>{if(err) reject(err)resolve(data)})})
}async function fn(){let r1=await read('./为学.txt')console.log(r1.toString())let r2=await read('./插秧诗.txt')console.log(r2.toString())let r3=await read('./观书有感.txt')console.log(r3.toString())
}fn()
③ async和await结合发送AJAX请求
function sendAJAX(url){return new Promise((resolve,reject)=>{const x=new XMLHttpRequest()x.open('GET',url)x.send()x.onreadystatechange=function(){if(x.readyState===4){if(x.status>=200&&x.status<300){resolve(x.response)}else{reject(x.status)}}}})}// promise then 方法测试// const result=sendAJAX('http://localhost:8000/server').then(value=>{// console.log(value)// })//async await测试async function main(){let result=await sendAJAX('http://localhost:8000/server')console.log(result)}
④ ES8对象方法扩展Object.values和Object.entries
1. Object.values()方法返回一个给定对象的所有可枚举属性值的数组
2. Object.entries()方法返回一个给定对象自身可遍历属性[key,value]的数组
3. Object.getOwnPropertyDescriptors
该方法返回指定对象所有自身属性的描述对象
const school={name:'尚硅谷',cities:['北京','上海','深圳'],subjects:['前端','Java','大数据','运维']}//获取对象所有的键console.log(Object.keys(school))//获取对象所有的值console.log(Object.values(school))//entriesconsole.log(Object.entries(school))const m=new Map(Object.entries(school))console.log(m)//对象属性的描述对象console.log(Object.getOwnPropertyDescriptors(school))const obj=Object.create(null,{name:{value:'尚硅谷',writable:true,enumerable:true,configurable:true}})
12. ECMAScript9 新特性
① 扩展运算符与rest参数
Rest参数与spread扩展运算符在ES6中已经引入,不过ES6中只针对于数组,在ES9中为对象提供了像数组一样的rest参数和扩展运算符
rest参数:对于对象(user)的支持
function connect({host,port,...user}){console.log(host)console.log(port)console.log(user)}connect({host:'127.0.0.1',port:3306,username:'root',password:'root',type:'master'})
扩展运算符:
const skillOne={q:'天音波',w:'金钟罩'}const skillTwo={e:'天雷破'}const skillThree={r:'猛龙摆尾'}//如果使用扩展运算符...skillOne,则解构为 q:'天音波',w:'金钟罩'const ms={...skillOne,...skillTwo,...skillThree}console.log(ms) //Object {q: "天音波", w: "金钟罩", e: "天雷破", r: "猛龙摆尾"}
② 正则扩展---命名捕获分组
没有命名捕获分组时:
//声明一个字符串let str="<a href='http://www.atguigu.com'>尚硅谷</a>"//提取url与标签文本const reg=/<a href='(.*)'>(.*)<\/a>/const result=reg.exec(str)console.log(result)console.log(result[1])
有命名分组捕获时:
命名分组语法:
?<任意名字>
//声明一个字符串let str="<a href='http://www.atguigu.com'>尚硅谷</a>"//提取url与标签文本const reg=/<a href='(?<url>.*)'>(?<text>.*)<\/a>/const result=reg.exec(str)console.log(result)console.log(result.groups.url)console.log(result.groups.text)
③ 正则扩展---反向断言
( ) | 标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用。要匹配这些字符,请使用 和和 |
. | 匹配除换行符 \n 之外的任何单字符。要匹配 . ,请使用 \. 。 |
用圆括号 () 将所有选择项括起来,相邻的选择项之间用 | 分隔。
() 表示捕获分组,() 会把每个分组里的匹配的值保存起来, 多个匹配值可以通过数字 n 来查看(n 是一个数字,表示第 n 个捕获组的内容)。
以下列出 ?=、?<=、?!、?<! 的使用区别:
exp1(?=exp2):查找 exp2 前面的 exp1。
(?<=exp2)exp1:查找 exp2 后面的 exp1。
exp1(?!exp2):查找后面不是 exp2 的 exp1
(?<!exp2)exp1:查找前面不是 exp2 的 exp1
//声明字符串let str='JS5201314你知道吗555啦啦啦'//正向断言const reg=/\d+(?=啦)/const result=reg.exec(str)console.log(result) //555//反向断言const reg1=/(?<=吗)\d+/const result1=reg1.exec(str)console.log(result1) //555
④ 正则扩展---dotAll模式
dot,即. 元字符,表示除换行符以外的任意单个字符
正则表达式-修饰符:
s | 特殊字符圆点 . 中包含换行符 \n | 默认情况下的圆点 . 是匹配除换行符 \n 之外的任何字符,加上 s 修饰符之后, . 中包含换行符 \n。 |
let str=`
<ul><li><a>肖申克的救赎</a><p>上映日期:1994-09-10</p></li><li><a>阿甘正传</a><p>上映日期:1994-07-06</p></li>
</ul>`const reg=/<li>.*?<a>(?<name>.*?)<\/a>.*?<p>(?<time>.*?)<\/p>/gslet resultwhile(result=reg.exec(str)){console.log(result.groups.name,result.groups.time)}
13. ECMAScript10 新特性
① 对象扩展方法Object.fromEntries
功能:接收一个二维数组或一个Map来创建数组
//二维数组const result=Object.fromEntries([['name','尚硅谷'],['subjects','JAVA,大数据,前端,云计算']])console.log(result) //Object {name: "尚硅谷", subjects: "JAVA,大数据,前端,云计算"}//Mapconst m=new Map()m.set('name','atguigu').set('age',20)const r=Object.fromEntries(m)console.log(r) //Object {name: "atguigu", age: 20}
该方法和Object.entries()互为逆运算,Object.entries()可以将对象转换为二维数组
const arr=Object.entries({name:'尚硅谷',subjects:'JAVA,大数据'})console.log(arr) //Array(2) [Array(2), Array(2)]
② 字符串方法扩展---trimStart和trimEnd
trimStart()清除字符串开头的空格
trimEnd()清除字符串结尾的空格
let str=' i love you 'console.log('----'+str+'----')console.log('----'+str.trimStart()+'----')console.log('----'+str.trimEnd()+'----')
③ 数组方法扩展---flat和flatMap
flat()可以将高维数组转换为低维数组,默认每次降低一个维度
const arr1=[[1,2],[4,5]]console.log(arr1.flat()) //Array(4) [1, 2, 4, 5]const arr2=[[[1,2],[3,4]],[[5,6],[7,8]]]console.log(arr2.flat()) //Array(4) [Array(2), Array(2), Array(2), Array(2)]
可以传递一个参数,代表深度
const arr2=[[[1,2],[3,4]],[[5,6],[7,8]]]console.log(arr2.flat(2)) //Array(8) [1, 2, 3, 4, 5, 6, 7, 8]
flatMap:它会遍历原数组的每一个元素, 并且会为每个元素都执行一次传入的回调函数,最终把所有元素执行回调函数返回的结果压缩成一个新数组,flatMap会返回一个新的数组,不会改变原数组的元素。
const arr=[1,2,3,4]const result=arr.flatMap(item=>[item*10])console.log(result) //Array(4) [10, 20, 30, 40]//对比mapconst result1=arr.map(item=>[item*10])console.log(result1) //Array(4) [Array(1), Array(1), Array(1), Array(1)]
④ Symbol.prototype.description
得到Symbol的描述值
let s=Symbol('尚硅谷')console.log(s.description) //尚硅谷
14. ECMAScript11 新特性
① 私有属性
#开头声明,表示私有属性
只能在类的内部访问,而不能通过外部访问
class Person{name#age#weightconstructor(name,age,weight){this.name=namethis.#age=agethis.#weight=weight}intro(){console.log(this.name,this.#age,this.#weight)}
}
let girl=new Person('小丽',23,'41kg')
console.log(girl) //Person {#age: 23, #weight: "41kg", name: "小丽"}
// console.log(girl.#age) Uncaught SyntaxError: Private field '#age' must be declared in an enclosing class
girl.intro() //小丽 23 41kg
② Promise.allSettled方法
allSettled方法的返回值始终是成功的
参数是多个Promise构成的数组,返回值中包含每一个Promise的状态的结果
const p1=new Promise((resolve,reject)=>{setTimeout(()=>{resolve('商品数据-1')},1000)})const p2=new Promise((resolve,reject)=>{setTimeout(()=>{reject('出错了')},1000)})const result=Promise.allSettled([p1,p2])console.log(result)
和Promise.allSettled很像的一个方法是Promise.all,但是Promise.all方法需要所有的Promise都成功才会返回成功,否则失败
③ String.prototype.matchAll方法
用来得到正则批量匹配的结果,在正则匹配提取数据方面非常实用
let str=`
<ul><li><a>肖申克的救赎</a><p>上映日期:1994-09-10</p></li><li><a>阿甘正传</a><p>上映日期:1994-07-06</p></li>
</ul>`let reg=/<li>.*?<a>(?<name>.*?)<\/a>.*?<p>(?<time>.*?)<\/p>/sgconst result=str.matchAll(reg)for(let v of result){console.log(v.groups.name,v.groups.time)}
// 运行结果
// 肖申克的救赎 上映日期:1994-09-10
// 阿甘正传 上映日期:1994-07-06
④ 可选链操作符
可选链操作符( ?. )允许读取位于连接对象链深处的属性的值,而不必明确验证链中的每个引用是否有效。
?. 操作符的功能类似于 . 链式操作符,不同之处在于,在引用为空( nullish ) ( null 或者 undefined) 的情况下不会引起错误,该表达式短路返回值是 undefined。
与函数调用一起使用时,如果给定的函数不存在,则返回 undefined
function main(config){//const dbHost=config && config.db && config.db.host;const dbHost=config?.db?.hostconsole.log(dbHost) //127.0.0.1
}
main({db:{host:"127.0.0.1",port:3306},cache:{host:"192.168.1.200",username:"admin"}
})
⑤ 动态import
静态引入:不管未来是否需要使用,直接先引入进来
动态引入:通过import()函数,传递模块路径,返回结果为一个Promise对象。同时这个Promise对象成功的值就是动态引入的模块所暴露的对象
document.getElementById('btn').onclick=function(){import('./hello.js').then(module=>{module.hello()})
}
⑥ BigInt类型
只需要在数字后面加上n即代表BigInt类型
主要用于大数值运算
//大整形let n=521nconsole.log(n,typeof n) //521n bigint//函数let n1=23console.log(BigInt(n1))let max=Number.MAX_SAFE_INTEGERconsole.log(max+1) //9007199254740992console.log(max+2) //9007199254740992console.log(BigInt(max)+BigInt(1)) //9007199254740992nconsole.log(BigInt(max)+BigInt(2)) //9007199254740993n
⑦ 全局对象globalThis
方便对全局对象操作,支持nodejs环境
console.log(globalThis)