es6-es13零碎知识点总结--自用

215 阅读14分钟

node版本最低为14.17.0,以防报错 重学ES6

对象字面量的增强写法(属性的简写 方法的简写 计算属性名)

2015之前对于对象的初始化

var name="xiong"
var age=18
var obj={
    name:name,
    age:age,
    bar:function(){}
}
obj[name + 133] ="计算属性"

es6增强写法-更加简洁

var name="xiong"
var age=18
var obj={
//property shorthand(属性的简写)
    name,
    age,
//method shorthand(方法的简写)
    bar(){
    },
    //computed shorthand(计算属性名的简写)
    [name +123]:'jhfks ',
}

解构(Destructuring):从对象或者数组中方便获取数据的方法

在开发中拿到一个变量时候,自动对其进行解构

对函数的参数进行解构

2015之前从数组中获取数据

var names= ['naerw','abx','dsd']
var items1=names[0]
var items2=names[1]
var items3=names[2]

es6解构从数组中获取数据

var [items1,items2,items3] =names
console.log(items1,items2,items3)
var [,itema,itemb] =names //只取后两位
var [itema,itemb,items3,items4]=names
//items4为undefined
var [itema,itemb,items3,items4=‘aaa’]=names
//items4直接赋值
var [items1,...newNames] =names
//结构出一个元素,后面的元素放到一个新数组中

对象的解构

var obj={
name:'xxx',
age:48,
height:1.88,
}
var {name, age,height}=obj;
    console.log(name, age,height);//xxx 48 1.88
var {age}=obj;
    console.log(age);   //48
//修改名称-重命名
var {name:newName}=obj;
    console.log(newName);//xxx 
obj.name='yyyyyyyyyyyy'
    console.log(name,obj);//xxx { name: 'yyyyyyyyyyyy', age: 48, height: 1.88 } 
//新增并给默认值
var {address:newAddress ='jkgdg'}=obj;
    console.log(obj)//{ name: 'yyyyyyyyyyyy', age: 48, height: 1.88 } 
    console.log(newAddress)//jkgdg 
    console.log(obj.address)//undefined
function bar({name,age}){
        console.log(name,age)
}
bar(obj)

var 变量声明 let 变量声明 const 常量声明 本质上传递的值无法修改

1.如果传递的是一个引用地址(内存地址),可以通过引用找到引用的对象,去修改对象内部的属性

    const aaaa={
        foo:'xxx',
    }
    aaaa.foo="bb"
    console.log(aaaa)

2.通过let和const定义的变量不能重复定义

3.作用域提升

var有变量提升的问题(在声明前就可以访问,但是为undefined)

let const没有作用域提升

console.log(a) //此时a被创建但是并不能访问
let  a='hsadkj'

在执行上下文的词法环境创建出来的时候,变量实际上已经被创建了,但是这个变量是不能被访问的

作用域提升:在声明变量的作用中,如果这个变量可以在声明之前被访问,那么我们称之为作用域提升

var有作用域提升,但是let、const没有作用域提升,但是会在执行上下文创建出来

4.let const var 和window的关系

在全局通过var来声明一个变量,事实上会在window上添加一个属性,但是 let、const 是不会给window上添加任何属性的。

var foo='foo'
console.log(window.foo)

上文中,每一个执行上下文会被关联到一个变量环境(VE variable Environment),在执行代码中变量和函数的声明也会作为环境记录(Environment Record)添加到VE中

对于函数来说,参数也会被作为环境记录添加到变量环境中

var保存在栈的go中,即window上

let和const、函数,声明的变量和环境记录是被添加到变量环境中:

js引擎在解析时,通过variableMap的一个HashMap来实现他们的存储的,

window对象是早期的GO对象,在最新的实现中其实是浏览器添加的全局对象,并且一直保持了window和var之间值的相等性

5.es6的块级作用域

块代码: if switch for都是块级作用域

{var foo='foo'}//声明一个变量
console.log(foo)

块级作用域-本质是块代码

在es6中新增了块级作用域,并且通过let、const、function、class声明的标识符时具备块级作用域的限制的:

{
let foo='foo'
function demo(){
console.log('demo function')
}
class Person{}
}

但是函数拥有块级作用域,但是外面依然可以访问的:因为引擎会对函数的声明进行特殊的处理,允许像var那样进行提升

声明对象的字面量

var obj={name:'why'}

es5里只有两个东西会形成作用域:全局作用域 函数作用域

大部分浏览器为了兼容以前的代码,让function是没有块级作用域的

const btns=document.getElementsByTagName('button')
for (var i = 0; i < 5; i++) {
(function(n){
	btns[i].onclick = function(){
		conosole.log("第"+n+“个按钮被点击”)
	}	
})(i)
}
console.log(i)//0 1 2 3 4 
//n没有只能找到外层的n,你是调用循环的i

es6
for (let i = 0; i < 5; i++) {
	btns[i].onclick = function(){
		conosole.log("第"+n+“个按钮被点击”)
	}
}

总结: var:历史遗留问题:没有块级作用域、作用域提升、window全局对象

const:优先推荐使用,当这个变量会被重新赋值的时候,在使用let

模板字符串 ${expression} 用于拼接字符串 里面可以是函数,可以进行计算

const age = 15;
const height=1.22;
const name='asda';
const mass=`my name is${name},age is ${age},height is${height}`
console.log(mass)

const info=`age double is ${age*2}`
function doubleAge(){
    return age *2
}
const fesss=`${doubleAge()}`
console.log(fesss)

标签模板字符串:调用函数的方式

function foo(m,n){
	console.log(m,n,'...')
}
//第一个参数依然是模块字符串中整个字符串,只是被切成多块,放到了一个数组中
//第二个参数是模块字符串中,第一个是${}
const age=18;
cosnt name="1ada"
foo `hello ${name} wo ${age}rld` //['hello','wo','rld'] 1ada ...
foo(name,age) //asda 15 ...

函数的默认值

es5
function foo() {
  var m = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'xxx';
  var n = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'yyy';
  console.log(m, n, '...');
}

es6
function foo(m='xxx',n='yyy'){
	console.log(m,n,'...')
}

對象参数和默认值以及结构

function fpp({name,age}={name:"ssmx",age:18}){
	console.log(name,age)
}
fpp({name:'copy',age:30})

function fpo({name = "why",age="23"}={}){
console.log(name,age)
}
fpo()

//有默认值的形参放在最后
function bar(x,y,z=20){
console.log(x,y,z)
}
bar(xx,10)

函数是有默认的length的值,即参数的长度;有默认值的函数的length属性会改变

function bar(x,y,z=20){
console.log(x,y,z)
}
console.log(bar.length)//2
默认值之后的参数不计入length的长度

函数的剩余参数(rest parameter)

如果最后一个参数是...为前缀的,那么它会将剩余的参数放到该参数中, 并作为一个 数组(类数组,无法使用数组的方法)

function cess(x,y,...args){
console.log(x,y)
console.log(args)
}
cess(20,30,10,40,60)

剩余参数和传参arguments有什么区别呢?

剩余参数只包含那些没有对应形参的实参,而arguments对象包含了传给函数的所有实参

arguments对象不是一个真正的数组,而rest参数是一个真正的数组,可以进行数组的所有操作

arguments是早期的ECMAScript中为了方便去获取所有的参数提供一个数据结构,而rest参数是ES6中提供并且希望以此来代替arguments

箭头函数:

箭头函数时没有显式原型的,所以不能作为构造函数,不能使用new来调用对象

展开函数

可以再函数调用/数组构造时候,将数组表达式或者string在语法层面展开

还可以在构造字面量对象时,将对象表达式按照key-value的方式展开

展开语法

在函数调用 、数组构造 、构建对象字面量时使用

const name=['a','b','v'];
const names='wuhfg';
function foo(x,y,z){
    console.log(x,y,z)
}
foo(...name)//a b v
foo(...names)//w u h

构造函数

const newNames=[...name,...names]
console.log(newNames) 
//
[  'a', 'b', 'v',  'w', 'u', 'h',  'f', 'g']

构件对象字面量时

const obj={...name,...names}
console.log(obj)//{ '0': 'w', '1': 'u', '2': 'h', '3': 'f', '4': 'g' }

注意:展开运算符实际进行的是一个浅拷贝

const obj={
    name:'jack',
    friend:{name:'kobe'}
}
const obk={...obj}
console.log(obj)//{ name: 'jack', friend: { name: 'kobe' } }

數值的表示方式

大的數值用_作为连接符号
const num =10_000_000_000_000
console.log(num)

Symbol基本数据类型

es6之前,对象的属性名(key)通过hashmap来进行实现
var obj={
	name:'jack',
    friend:{name:'kobe'}
}
虽然name没有用“”包裹起来,但是在底层里还是用字符串“”进行处理

这样会导致属性名重复冲突的问题:
在原有的对象上添加一个新的属性和值,但是我们在不确定它原来内部有什么内容的情况下,容易造成冲突,从而导致覆盖掉它内部的某个属性
在混入时,也会导致覆盖
在call bind操作的时候,会导致原有的属性被重写

Symbol会生成一个独一无二的值,symbol是通过symbol函数来生成的,生产后可以作为属性名,也就是说在es6中,对象的属性名可以使用字符串,也可以是symbol

每次Symbol创建的值是不同的,我们可以在创建Symbol值的时候,传入一个描述description(number | string)

symbol的使用

1.symbol作为key

const s2=Symbol('aaa')

2.在定义对象字面量使用

const obj={
	[s1]:"abc",
	[s2]:'cab'
}
obj[s3]='xxxx'
//{ [Symbol()]: 'abc', [Symbol(aaa)]: 'cab', [Symbol(xxx)]: 'xxxx' }

3.Object.defineProperty方式

const s4=Symbol();
Object.defineProperty(
    obj,s4,{
        enumerable:true,
        configurable:true,
        writable:true,
        value:'jkhk',
    }
)

注意:不能通过.语法去获取

  1. 使用Symbol作为key的属性名,在遍历Object.keys等中是获取不到这些Symbol值的

获取Symbol的数值

console.log(Object.getOwnPropertyNames(obj))//[]console.log(Object.keys(obj))//[]
都获取不到Symbol的key
console.log(Object.getOwnPropertySymbols(obj))
循环获取
const sKeys=Object.getOwnPropertySymbols(obj)
for(const sKey of sKeys ){
    console.log(obj[sKey])
}
/*
abc
cab
xxxx
jkhk
*/

5.希望symbol的值在某些情况下一致,用Symbol.for(描述)

const sa=Symbol.for('aa')

const sb=Symbol.for('aa')

console.log(sa === sb) //true

Symbol.keyFor(Symbol)

const ww=Symbol.keyFor(sa)
console.log(ww)//aa,此时已经不是symbol对象

const uuu=Symbol.for(ww)
console.log(ww === uuu) //false
console.log(sa === uuu)//true

Set WeakSet

set 元素不能重复,通过set构造函数,暂时没有字面变量的创建方法-----去重,

set里的元素保存在不同的内存的地址中

set的元素可以传入可迭代的对象

cosnt set=new Set();
新增 set.add(10)
添加不同对象---会成功添加两个
set.add({})
set.add({})
添加相同对象---只会添加一个
cosnt obj={}
set.add(obj)
set.add(obj)

去重

const arr=[11,11,11,22,33,{},{}]
const arrSet=new Set(arr)
const arry=Array.from(arrSet)
或者 const arry=[...arrSet]
console.log(arry)//[ 11, 22, 33, {}, {} ]

常见属性和方法

size属性,返回元素的个数

set.size
增加 set.add(dd)
删除 set.delete(22)
清除 set.clear()
包含 set.has(22)
遍历 set.forEach(item =>{
console.log(item)
})

WeakSet

区别:1.WeakSet中只能存放对象类型,不能存放基本数据类型

//Invalid value used in weak set
const weakSet = new WeakSet()
weakSet.add(10)

2.weakSet对元素的引用是弱引用,如果没有其他引用对某个对象进行引用, 那么GC可以对该对象进行回收

WeakSet只是对对象的弱引用,如果我们遍历获取到其中的元素,那么有可能造成对象不能正常的销毁,所以存到WeakSet中的对象是没办法获取的

Map存储映射关系

1.es6之前,我们使用对象来存储映射关系

对象存储映射关系,只能用字符串作为属性名

某些情况下无法使用其他类型作为key,比如对象,这个时候会自动将对象转换成字符串来作为key

对象储存映射
const obj1={name:"xxx"}
const obj2={name:"yyy"}
​
const info={
    [obj1]:'aaa',
    [obj2]:'bbb'
}
console.log(info)//{ '[object Object]': 'bbb' }
toString将对象转换成字符串
​

Map存储对象:map允许我们对象类型来作为key的,构造方法的使用

1.new之后,set进去
const map1=new Map();
map1.set(obj1,'aaa')
​
2.直接new的时候,塞进去,插入时需要使用[]进行包裹,然后以键值对进行传入[xxx,xxx]
const map2=new Map([[obj2,"bbb"],[2,"sss"]]);

常见的属性和方法

map.size()长度
​
map.set("22","2sss")新增
​
map.get(key) 获取
​
map.has()是否含有
​
map.delete("xxx")删除
​
map.forEach((item,key) =>{console.log(item,key)}) 遍历map
for(const [key,value] of map2){ console.log(key,value)}//遍历且直接解构

WeakMap

区别一:WeakMap的key只能使用对象,不接受其他类型作为key(不能使用基本数据类型作为key)

区别二:WeakMap的key对对象的引用是弱引用,如果没有其它引用引用这个对象,那么GC可以回收该对象了

区别三:无法进行遍历

WeakSet 只能存放对象 WeakMap:key只能对象,只能通过WeakMap.array.forEach()

常用方法和map一样(get set has delete)

WeakMap没有size属性

Array includes方法 ES7

是否包含,之前是用indexOf(通过索引值判断是否存在)

区别是对于nan的判断

const aa=["aaa","bbb","nnn","eee",NaN];
if(aa.includes("aaa")){
    console.log("有")
}
// 第一个参数:需要查询的元素,第二个参数:从第几个算起来

指数运算符:平方运算符 **

const cc= 3 ** 3  //27const bb=Math.pow(3,3) //27

Object.values

const obj={
    name:'xxx',
    age:20,
}
console.log(Object.keys(obj))//[ 'name', 'age' ]    返回数组的key
console.log(Object.values(obj))//[ 'xxx', 20 ]      返回数组的value
console.log(Object.values(["aaa","bbb","nnn","eee",NaN]))//["aaa","bbb","nnn","eee",NaN]        传入一个数组,返回数组本身
console.log(Object.values("adgvsx"))//[ 'a', 'd', 'g', 'v', 's', 'x' ] 传入一个字符串,返回字符串所有的字符,字符防在一个数组里返回

Object.entries获取到一个数组,数组中会存放可枚举属性的键值对数组

console.log(Object.entries(obj)) //[ [ 'name', 'xxx' ], [ 'age', 20 ] ]
例如获取元素进行遍历
const rrr=Object.entries(obj);
rrr.forEach(item =>{
    console.log(item[0],item[1])
}) //name xxx   age 20

用途

普通的对象遍历的时候,普通对象没有实现 iterator 接口,所以可以用Object.entries 得到的键值对数组就可以使用 for...of 遍历

let obj = {
  a: 1,
  b: 2
}
​
for (let value of obj) {
  console.log(value)
}//Uncaught TypeError: obj is not iterablefor (let [key, value] of Object.entries(obj)) {
  // ...
}

string padding

某些场景需要对字符串前后进行填充,来实现某种格式话的效果,增加 padStart 和 padEnd方法,分别对字符串的首尾来进行填充

const message= "ja";
const mesajg=message.padStart(10,"8").padEnd(20,"1") //长度  填充物
console.log(mesajg)

同样的使用replace也可以达到相同效果

处理卡号的案例
const cardNum="2131465467567897680"
const lastFourCard =cardNum.slice(-4)
console.log(lastFourCard) //7680
const finalcard=lastFourCard.padStart(cardNum.length,"*")
console.log(finalcard)  //***************7680

trailing-commas(尾随逗号):在ES8中,我们允许在函数定义和调用时多加一个逗号:

//结尾的逗号(JS引擎依然能解析,不会报错)
function foo(m,n,){
​
}
​
foo(20,30,)

object.getOwnPropertyDescriptors获取对象的所有的属性描述符

const obj={
    name:'xxx',
    age:20,
}
console.log(Object.getOwnPropertyDescriptors(obj))
/*
{
  name: {
    value: 'xxx',
    writable: true,
    enumerable: true,
    configurable: true
  },
  age: { value: 20, writable: true, enumerable: true, configurable: true }
}
*/

Es9

async iterators

Object spread operators ... 展开运算符

const obj ={name :'xx'}
cosnt objx ={...obj}

Promise finally

ES10

flat flatMap fromEntries

flat()会按照一个可指定的深度递归遍历数组,并将所有元素和遍历到的子数组中的元素合并为一个新数组返回

const nums=[10,[2,9],[[3,9],8,[8,5]]]
flat会将数组进行一次降维
const newNums=nums.flat()
console.log(newNums) //[ 10, 2, 9, [ 3, 9 ], 8, [ 8, 5 ] ]
​
const newNums1=nums.flat(1)
console.log(newNums1)//[ 10, 2, 9, [ 3, 9 ], 8, [ 8, 5 ] ]
​
const newNums2=nums.flat(2)
console.log(newNums2)
/*
[
  10, 2, 9, 3,
   9, 8, 8, 5
]
*/

flatMap首先使用映射函数映射每一个元素,然后将结果压缩成一个新数组

1:flatMap是先进行map操作,再做flat操作

2.flatMap中的flat相当于深度为1

const nums2=[11,22,33]
const newnums2=nums2.flatMap(item =>{
    return item**2;
})
console.log(newnums2)// 
​
const messer=["My Name","Hello Word","My name is xiong jun yan"]
console.log(
    messer.map(item =>{
        return item.split(" ")
    })
)
/*
[
  [ 'My', 'Name' ],
  [ 'Hello', 'Word' ],
  [ 'My', 'name', 'is', 'xiong', 'jun', 'yan' ]
]
*/
console.log(
    messer.flatMap(item =>{
        return item.split(" ")
    })
)
/*
[
  'My',    'Name',
  'Hello', 'Word',
  'My',    'name',
  'is',    'xiong',
  'jun',   'yan'
]
*/

fromEntries 将entries转换成对象

const objx={
    name:'xxx',
    age:20,
}
​
const entries =Object.entries(objx)
1.
const newObj={...objx}
console.log(entries)//[ [ 'name', 'xxx' ], [ 'age', 20 ] ]
for (const i of entries){
    newObj[i[0]] = i[0]
}
console.log(newObj)//{  name: 'xxx', age: 20 } 
for in 拿到了里面的索引值 
for of 拿到里面的元素
​
2.
const obk=Object.fromEntries(entries)
console.log(obk )//{  name: 'xxx', age: 20 } 

ES11

BigInt:用来表示过大的数字,在数字后加一个n

之前MAX_SAFE_INTEGER表示最大的安全数字
const maxInt = Number.MAX_SAFE_INTEGER
console.log(maxInt) //9007199254740991
console.log(maxInt +1)  //9007199254740992
console.log(maxInt +2) //9007199254740992BigInt和小数字number无法进行计算
const bigInt = 9007199254740991n
console.log(bigInt +BigInt(2))  转换成BigInt之后进行计算

所有的计算,都需要进行隐式转换

空值合并运算 ??

作用是当一个表达式是nullundefined时,为变量设置一个默认值

let f00 =null;
const f99 =f00 ?? "xxxx"
console.log(f99)

可选链 代码在进行null和undefined判断的时候更加清晰和简洁

const obj={
    name:'xxx',
    age:20,
    friends:[{
        name:"x",
        age:18
    }]
}
1.
if(obj.friends && obj.friends[0].name){
console.log(obj.friends && obj.friends[0].name) //x
}
2.
console.log(obj.friends[0]?.name) //x

GlobalThis 获取某一个环境下的全局对象,比如node

在node下 window是undefined

console.log(globalThis)//全局对象
console.log(window)//undefined
console.log(this) //{}

Es11,for..in用于遍历对象的key 模块化 Promise.allSettled

ES12

finalizationRegistry对象可以让你在对象被垃圾回收时候请求一个回调

当一个在注册表中注册的对象被回收时候,请求在某个时间点上调用一个清理回调(finalizer)

可以通过register方法,注册任何你想要清理回调的对象,传入该对象和所含的值

发布-订阅模式

const finalRegistry =new FinalizationRegistry((value) =>{
    console.log("FinalizationRegistry对象被销毁了",value)
});
const obj={name:"obj1"};
const weakMap=new WeakMap()
weakMap.set(obj,"aaa")
finalRegistry.register(weakMap,"objxx");

WeakRef对象包含对对象的弱引用,这个弱引用被称为weakRef对象的target或者是referent,对对象的若引用值当该对象被GC回收的时候,不会阻止GC回收行为

WeakRef.prototype.deref();返回当前对象所绑定的target对象,

如果该对象已经被GC则返回undefined

尽量避免使用

const finalRegistry =new FinalizationRegistry(() =>{
    console.log("FinalizationRegistry对象被销毁了")
});
const obj={name:"obj1"};
const weakRef=new WeakRef(obj);
finalRegistry.register(weakRef);
console.log(weakRef.dref().name)

逻辑运算 新增的语法糖

||= 逻辑或赋值运算

let message=undefined
​
message =message || "xxx";
等于 message ||= "xxx";//'xxx'

&&=逻辑与

let foo0={
    name:'xxx',
}
foo0 = foo0 && foo0.name
等于 foo0 &&= foo0.name

??=逻辑空

let message=undefined
message =message ?? "xxx";
等于 message ??= "xxx";//'xxx'

hasOwn(obj,propKey)

Object新增一个静态方法(类方法):hasOwn(obj,propKey):该方法用于判断一个对象中是否有某个自己的属性

const objx={
    name:'xxx',
    age:20,
    __proto__:{
        address:"广州市"
    }
}
console.log(objx.address)
console.log(Object.hasOwn(objx,"name"))//true
console.log(objx.hasOwnProperty("name"))//true

Object.hasOwn(obj对象,propKey属性) 和Object.prototype.hasOwnProperty的区别

1.防止对象有自己的一个Object.prototype.hasOwnProperty方法,

2.本身没有该方法,后续新增的情况下,hasOwnProperty无法判断出后增的数据

const info =Object.create(null)
info.name ="xxxssss"
console.log(info.hasOwnProperty("name"))
// info.hasOwnProperty is not a function
//此时找到的对象是null,所以hasOwnProperty为空
console.log(Object.hasOwn(info,"name"))//true