目录
一、ECMAScript相关介绍
二、ES6新特性
(一)let关键字
(二)const关键字(定义常量、多用于数组和对象)
(三)变量结构赋值
(四)模板字符串
(五)简化对象写法
(六)箭头函数
(七)函数参数的默认值
(八)rest参数(剩余参数)
(九)扩展运算符
扩展运算符的应用:
①数组合并
②数组克隆(浅拷贝)
③将伪数组转为真正的数组
(十)symbol
(十一)迭代器 Iterator
(十二)生成器
(十三)Promise
(十四)集合
(十五)Map(类似对象)
(十六)class类
(十七)数值扩展
(十八)对象方法扩展
(十九)模块化
1、初识module
2、Module基本用法
3、模块化语法
三、ES7新特性
四、ES8新特性
(一)async 和 await
(二)对象方法扩展
五、ES9新特性
六、ES10新特性
(一)对象扩展
(二)字符串扩展
(三)数组扩展
七、ES11新特性
(一)私有属性
(二)promise.allSettled()方法
(三)str.matchAll()
(四)可选链操作符 ?.
(五)动态import
(六)BigInt(新数据类型),BigInt()函数
(七)globalThis变量
ECMAScript 是由 Ecma 国际通过ECMA-262 标准化的脚本程序设计语言。平时经常编写的JavaScript,是ECMAScript 的一种实现,所以ES新特性其实指的就是JavaScript的新特性。
ES6 加入许多新的语法特性,使编程的实现更简单、高效
ES标准列表:
http://www.ecma-international.org/publications/standards/Standard.htm
ES兼容性:
ECMAScript 6 compatibility table
1、同一变量不能重复声明,var可以。
//报错
let a=1;
let a=2;
2、let遵循块级作用域(全局声明的let变量不会变成windows属性)。
ES5有三种作用域:全局、函数、eval。ES6新增块级作用域。
3、不存在变量提升。
不允许在声名之前使用,会报错。但var可以,在声明之前使用会有一个初始值undefined。
4、不影响作用域链。
let a=1;
function fn(){
console.log(a);
}
fn();
块级作用域:除了对象 {}
,函数 {}
(函数作用域)之外的一切 {}
都属于块级作用域。
作用域链:内部函数访问外部函数的变量,采取的是就近链式查找的方式来决定最终取那个值。内层作用域 ——> 外层作用域 ——> 全局作用域
1、一定要赋初始值。
2、一般常量名使用大写。
3、常量的值不能修改。
4、const也遵循块级作用域。
5、对于数组和对象的修改,不算做对常量的修改,不会报错。
const array1=['a','b','c'];
array1.push('c');
ES6允许按照一定模式从数组和对象中提取值,对变量进行赋值,即为解构赋值(个人认为有点像二维数组)。适用于频繁使用的对象方法、数组元素。
数组解构赋值:
const SEA=['a','b','c','d'];
let [aa,bb,cc,dd]=SEA;
console.log(aa);
console.log(bb);
console.log(cc);
console.log(dd);
对象解构赋值:
const object={
name:'Rose',
age:'18',
herWork:function(){
console.log('Hi');
},
herStory(){
console.log('Bye');
}
}
let {name,age,herWork}=object;
let {herStory}=object;
新的声明字符串的方式 ``:①在模板字符串里面可以直接使用enter换行,无需使用
。
②变量拼接:
//变量拼接
let one='小猪';
let two=`${one}佩奇`;
ES6允许在{ }里面直接写入变量和函数,作为对象的属性和方法。
let name='魔法学院';
let address='earth';
const school={
name, //name:name,
address
}
phone(){}//phone:function(){}
ES6允许使用箭头定义函数,(参数)=>函数体。
箭头函数的作用:1、箭头函数比函数表达式更简洁。
2、解决 this 的指向问题。箭头函数不会创建自己的this,它只会从自己的作用域链向上一层继承this。
( call() 方法可以改变函数内部this的值)
let fn=function(){
}
let fn=()=>{
}
箭头函数特性:①this是静态的,this始终指向函数声明时所在作用域下的this的值。
②不能作为构造函数实例化对象。
③不能使用arguments变量。
(arguemnts是函数的内置对象,存储其调用函数时传入的所有实参)
//②报错
let Person=(name,age)=>{
this.name=name;
this.age=age;
}
let me=new Person('Mei',20);
console.log(me)
当箭头函数的形参有且仅有一个时可以省略();当函数体只有一句执行语句时,{ }可以省略,此时return也必须省略,而且语句的执行结果就是函数的返回值。
箭头函数适用于与this无关的回调,eg:定时器、数组的方法回调
箭头函数不适用于与this有关的回调,eg:事件回调、对象的方法
ES6允许给函数的形参赋初始值,且默认值可以与解构赋值结合。(具有默认值的参数,一般位置要靠后)。
function add(a,b,c=1){
return a+b+c;
}
let result=add(1,2);
console.log(result);//result==4
ES6引入rest参数,用于获取函数的实参,用来代替arguments。(...变量名)
rest参数必须要放到参数最后,只能是最后一个参数。
function data(...gain){
console.log(gain);
}
data('a','b','c');
剩余语法(Rest syntax 也可以叫剩余参数)看起来和展开语法完全相同都是使用 ...
的语法糖,不同之处在于剩余参数用于解构数组和对象。从某种意义上说,剩余语法与展开语法是相反的:展开语法将数组展开为其中的各个元素,而剩余语法则是将多个元素收集起来成为一个整体。
剩余语法看起来和展开语法完全相同,不同点在于,剩余参数用于解构数组和对象。
"..."能将 数组 转换为逗号分隔的 参数序列。
const singers=['周杰伦','五月天','周深']
function grand(){
console.log(arguments);
}
grand(...singers);
const color=['pink','green','blue']
const fruits=['banana','apple','orange','watermelon']
const colorfulFruits=[...color,...fruits]
const mood=['hao','henhao','feichanghao']
const mood2=[...mood]
ES6引入一种新的原始数据类型Symbol,表示独一无二的值,是动态形成的。
1、symbol的特点:①symbol值是唯一的,用来解决命名冲突的问题。
②symbol的值不能与其他数据类型进行运算。
③symbol定义的对象属性不能使用for...in循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有键名。
2、Symbol创建:
//函数
let a=Symbol();
//对象
let b=Symbol.for();
3、向对象添加Symbol类型的属性和方法:
//方法一
//向game对象中添加Symbol类型的方法up down
let game={}
let methods={
up:Symbol(),
down:Symbol()
}
game[methods.up,methods.down]=function(){
console.log()
}
//方法二
let study={
name:"good",
[Symbol()]:function(){
}
}
4、Symbol内置属性
方法 | 描述 |
---|---|
Symbol.hasInstance |
当其他对象使用 instanceof 运算符,判断是否为该对象的实例时,会调用这个方法 |
Symbol.isConcatSpreadable |
对象的 Symbol.isConcatSpreadable 属性等于的是一个布尔值,表示该对象用于Array.prototype.concat() 时,是否可以展开 |
Symbol.species |
创建衍生对象时,会使用该属性 |
Symbol.match |
当执行 str.match(myObject) 时,如果该属性存在,会调用它,返回该方法的返回值。 |
Symbol.replace |
当该对象被 str.replace(myObject) 方法调用时,会返回该方法的返回值。 |
Symbol.search |
当该对象被 str.search(myObject) 方法调用时,会返回该方法的返回值。 |
Symbol.split |
当该对象被 str.split(myObject) 方法调用时,会返回该方法的返回值。 |
Symbol.iterator |
对象进行 for...of 循环时,会调用 Symbol.iterator 方法,返回该对象的默认遍历器 |
Symbol.toPrimitive |
该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值。 |
Symbol. toStringTag |
在该对象上面调用 toString() 方法时,返回该方法的返回值 |
Symbol. unscopables |
该对象指定了使用 with 关键字时,哪些属性会被 with 环境排除。 |
该图表来源:MurphyChen's Notes ,侵权删
迭代器(Iterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署Iterator接口,就可以完后遍历操作。
1、ES6创造了一种新的遍历命令for...of循环,Iterator接口主要供for...of消费。
const eat=['啤酒','炸鸡','我好饿']
//使用for...of遍历数组(for...in获取的是数组值的索引)
for(let v of eat){
console.log(v);
}
2、原生具备Iterator接口的数据类型:array、arguments、set、map、string、typedArray、nodeList。
3、迭代器工作原理:
a)创建一个指针对象,指向当前数据结构的起始位置;
b)第一次调用对象的next方法,指针自动指向数据结构的第一个成员;
c)接下来不断调用next方法,指针一直往后移动,直到指向最后一个成员;
d)每调用next方法返回一个包含value和done属性的对象。
迭代器适用于自定义遍历数据。
// 声明一个对象
const cartoon={
name:'xiaoLiYu',
mbrs:[
'xialiyu',
'laipishe',
'xiaomei'
],
[Symbol.iterator](){
let index=0;
let _this=this;
return{
next:function(){
if(index<_this.mbrs.length){
const result={value:_this.mbrs[index],done:false}
index++;
return result;
}else{
return {value:undefined,done:true}
}
}
}
}
}
// 遍历对象
for(let v of cartoon){
console.log(v);
}
生成器函数是ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同。传统函数所实现异步编程的方式是回调函数。
1、生成器函数的特殊点:声明时要加 * ,调用时需要使用 next 方法,yield 语句可以看作是分隔符,每调用一次next,就执行一块yield。
function * fnc(){
yield '一只小猪';
yield '被烤了';
}
let iterator=fnc();
iterator.next();
iterator.next();
2、生成器函数参数
在next()内可以传入实参,其结果会在yield中调用
// 模拟获取用户数据、订单数据、商品数据
function getUsers(){
setTimeout(()=>{
let data='用户数据'
// 调用next方法,并且将数据传入
iterator.next(data)
},1000)
}
function getOrders(){
setTimeout(()=>{
let data='订单数据'
},1000)
}
function getGoods(){
setTimeout(()=>{
let data='商品数据'
},1000)
}
function *gen(){
let users= yield getUsers();
console.log(users);
yield getOrders();
yield getGoods()
}
// 调用生成器函数
let iterator=gen()
iterator.next()
Promise是ES6引入的异步编程的新的解决方案(即解决层层嵌套的回调函数(回调地狱)的问题)。语法上promise是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果。
//Promise基本语法
// 实例化Promise对象
const p=new Promise(function(resolve,reject){
setTimeout(function(){
//成功
// let data='数据库中的用户数据'
// // resolve成功函数
// resolve(data)
// 失败
let err='数据读取失败'
reject(err)
},1000)
})
// 调用Promise对象的then方法 value成功的实参 reason失败的实参
p.then(function(value){
console.log(value);//成功
},function(reason){
console.log(reason);//失败
})
1、Promise的三种状态:Pending初始状态、resolved成功(fulfilled)、rejected失败。
2、Promise的then方法的链式调用:
p.then(value=>{},reason=>{}).then(value=>{},reason=>{})
3、promise的catch方法:用于指定promise对象失败的回调。
const p=new Promise((resolve,reject)=>{
setTimeout(()=>{
// 仅设置对象的状态失败
reject("出错啦!")
},1000)
})
// p.then(function(value){},function(reason){
// console.error(reason);
// })
p.catch(function(reason){
console.error(reason);
})
补:console.log:输出普通信息
console.info输出提示性信息
console.error输出错误信息
console.warn输出警告信息
console.debug输出调试信息
ES6提供了新的数据结构Set(集合)。类似于数组,但成员的值都是唯一的,集合实现了Iterator接口,所以可以使用扩展运算符和for...of...进行遍历。
1、集合set的属性和方法:
size 返回集合的元素个数
add 增加一个新元素,返回当前集合
delete 删除元素,返回boolean值
has 检测集合中是否包含某个元素,返回boolean值
//声明一个集合
let s=new Set(['a','b','c','b'])
console.log(s)//去重
console.log(s.size)
ES6提供了Map数据结构,类似于对象,也是键值对的集合,但是“键”的范围不再局限于字符串 ,各种类型的值(包括对象)都可以当作键。Map也实现了Iterator接口,可以使用扩展运算符和for...of...进行遍历。
1、Map的属性和方法:
size 返回Map的元素个数
set 增加一个新元素,返回当前Map
get 返回键名对象的键值
has 检测Map中是否包含某个元素,返回boolean值
clear 清空集合,返回undefined
//声明Map
let m=new Map()
//添加元素(键,值)
m.set('status','好困')
m.set('change',function(){
console.log("等会再困")
})
m.set('city',['成都','天津','咸阳'])
ES6提供了更接近传统语言的写法,引入了class这个概念,作为对象的模板。通过class关键字,可以定义类。基本上,ES6的class可以看作是一个语法糖,其绝大部分功能ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
1、super()既可以作为函数使用,又可以作为对象使用。
作为函数调用时,代表父类的构造函数;作为对象使用时,在普通方法中,指向父类的原型对象,在静态方法中,指向父类。
2、constructor(),prototype有一个constructor的属性,默认是指向prototype所在的构造函数。是类的默认方法,通过new命令生成对象实例时,自动调用该方法。
3、getter()和setter()是对某一个对象属性进行方法的绑定。getter通常用于对动态属性的封装,setter用于添加更多的控制和判断。
1、Number.EPSION表示js的最小精度。
2、二进制0b 八进制0o 十六进制0x
eg: let a=0b1010,即十进制的10
3、Number.isFinite用于检测一个数值是否为有限数,返回结果为布尔值
4、Number.isNaN检测一个数值是否为NaN
5、Number.parseInt Number.parseFloat将字符串转为整数(会截断)
6、Number.isInteger判断是否为整数
7、Math.trunc将数字的小数部分抹掉
8、Math.sign判断一个数到底为正数 负数 还是零,返回结果1 -1 0
1、Object.is判断两个值是否完全相等,返回结果为boolean,与===有一定区别
2、Object.assign对象的合并,对于重复的参数属性,后者会覆盖前者
3、Object.setPrototypeOf设置原型对象
模块(module):一个一个的局部作用域代码块。
模块化:是指将一个大的程序文件拆分成许多小的文件,然后将文件组合起来。
模块化优势:防止命名冲突、代码复用、高校维护
ES6 之前的模块化规范有:
- 普通的 HTML、JS 是本地文件环境,地址以 file 协议开头,服务器则以 http 或 https 开头。
- Module 要生效,必须在服务器环境下才能执行。方法:VSCode 中使用 Live Server 拓展,WebStorm 默认就是服务器环境。
- 在使用 script 标签加载的时候,需要加上 type="module",否则就以普通 JS 文件的形式引入了,就不是模块了
模块功能主要由两个命令构成:import 和 export
import 命令用于导入
export 用于导出,规定模块的对外接口
xxx.js
//1、分别暴露
export xxx
//2、统一暴露
export {xxx1,xxx2}
//3、默认暴露
export default{
...
}
1、Array.prototype.includes
includes 方法用来检测数组中是否包含某个元素,返回结果为布尔类型。
2、指数操作符
在ES7中引入指数运算符 ** ,用来实现幂运算,功能与 Math.pow 相同
async 和 await两种语法结合可以让异步代码像同步代码一样
(异步编程的解决方案:生成器函数、promise、async和await)
①async函数
该函数返回值为promise对象,该promise对象的结果由async函数执行的返回值(return)决定。
async function fn(){
}
②await表达式
//创建promise对象
const p=new Promise((resolve,reject)=>{
resolve("成功")
//reject("失败“)
})
//await函数
async function main(){
//try{
let result=await p
console.log(result)
//}catch(e){
//console.log(e)
}
})
//调用函数
main()
1、Object.values()方法返回一个给定对象的所有可枚举属性值的数组
2、Object.entries()方法返回一个给定对象自身可遍历属性[key,value]的数组,对象转换为二维数组
3、Object.getOwnPropertyDescriptors()该方法返回指定对象所有自身属性的描述对象
1、rest参数与spread扩展运算符在ES6中已经引入,不过只针对数组,在ES9中为对象提供了像数组一样的rest参数和扩展运算符。
function fn({host,port,...user}){
....
}
fn({
host:'127.0.0.1',
port:3306,
username:'root',
password:123
})
2、正则(我不会)
hash函数,是将任意长度的数据映射到有限长度的域上。
Object.fromEntries用于创建对象,参数接收一个二维数组或Map。是ES8中的Object.entries()的逆运算。
//二维数组
const result=Object.fromEntries([
['name','red'],
['xueke','java,web,SQL']
])
//MAP
const m=new Map()
m.set('name','haokun')
const result=Object.fromEntries(m)
console.log(result)
trimStart和trimEnd用于指定清除某个字符串左侧或右侧的空白字符。
let str=' xxx '
console.log(str.trimStart());
flat 可以数组降维, num 表示降维级数
const arr=[1,2,3,[4,5]]
console.log(arr.flat(num))
//>[1,2,3,4,5]
flatMap falt和Map方法的结合,Map返回结果如果是多维数组,可以降维
const arr=[1,2,3,4]
const result=arr.flatMap(item=>[item*10])
console.log(result)
(四)Symbol扩展
JS的7种数据类型:undefined、string、symbol、object、null、number、boolean
Symbol.prototype.description 获取symbol的字符串描述
//创建Symbol
let s=Symbol('haokun')
console.log(s.description)
对属性的封装,防止外部直接操作
Promise.all()
方法只适合所有异步操作都成功的情况,如果有一个操作失败,就无法满足要求。
Promise.allSettled()
方法,用来确定一组异步操作是否都结束了(不管成功或失败)。
二者都用于批量异步任务。
该方法返回一个包含所有匹配正则表达式的结果及其分组捕获组的迭代器。适于数据的批量提取。
?. 允许读取位于连接对象链深处的属性的值,而不必明确验证链中的每个引用是否有效。
?.
操作符的功能类似于 .
链式操作符,不同之处在于,在引用为空(nullish ) (null 或者 undefined) 的情况下不会引起错误,该表达式短路返回值是 undefined
。与函数调用一起使用时,如果给定的函数不存在,则返回 undefined
。
xxx?.zzz,可选链操作符会判断xxx是否存在,存在才会读取zzz。
function main(config){
//过去方式
//const dbHost=config && config.db && config.db.host
//可选链操作符?.
const dbHost=config?.db?.host
可实现按需加载(懒加载)
xxx.js
const btn=document.getElementById('btn')
btn.onclick=function(){
import('./server.js).then(modules=>{ //返回结果是一个promise对象
module.hello()
})
}
用于进行更大的数值运算。表现方式,在普通整数数值后面加一个n。
注意:BigInt类型的数值不能直接与普通数值类型做运算。
//表现形式
let a=65n;
//BigInt函数
let max=Number.MAX_SAFE_INTEGER;//最大安全整数
console.log(BigInt(max)+BigInt(7));
作用:始终指向全局变量