A、ES6
A-1、let声明变量
A-1-1 块级作用域
1、在之前我们用var声明变量的时候,很容易让我们在for或者if定义的变量暴露出来,从而污染全局变量
例如:
{
let i = 100;
}
console.log(i)
//for 循环
for(let i=0;i<5;i++){
}
console.log(i)
//if循环
if(true){
let i = 100;
}
console.log(i)
保存后运行在浏览器控制台中就能看到它无法访问到这个变量,只在他所在的这个块里运行。
案例
2、let
不允许重复声明
let a = 1
let a = 1
console.log(a)
保存后运行会在控制台报错
3、没有变量提升
就是还没声明之前就可以使用
console.log(myname)
var myname = "isWhj.ReTurN_N"
会变成undefined(未声明)
而let不会出现声明提前的现象
例如:
let myname = "isWhj.ReTurN_N"
function test(){
console.log(myname)
let myname = "Fking Whj"
}
test()
结果:报错
因为:暂存性死区在我们使用let变量之前,这个变量是不可用的,但是这个变量是存在的。如果我们没有let一行,那么他就会访问外面的myname这个变量,最后test出来的就是isWhj.ReTurN_N
。这就是暂存性死区
4、不与顶层对象挂钩
let myage = 1
console.log(window.myage)
保存后就会出现undefined
A-2 const声明常量
ES6声明带来的新的关键字。
常量 const
const myname = "isWhj"
myname = "NotWhj"
结果:报错,无法定义常量
大致特性都和let的1、2、3、4一致,也是块级生效的
面试题:用const定义的常量就一定不能被改变吗?
答案:不一定
const myobj = Object.freeze({
name:"whj"
age:1100
})
myboj.name = "o.O"
console.log(myboj)
A-3 变量解构赋值
解构赋值:就是快速的从对象或者数组中取出成员的一个语法方式
A-3-1 对数组的解构赋值
1、快速的从对象中获取成员
//ES5 中获取对象的方法
const obj = {
name:'whj',
age:100,
gender:'man'
}
let name = obj.name
let age = boj.age
let gender = obj.gender
2、用结构对象在获取对象中的成员
let arr = [1,2,3]
let [a,b,c] = arr
//互换
[x,y] = [y,x]
//默认为1
let [x=1] = [100]
//重命名
code:co
//赋值
err="没有错误"
3、数组中的数字交换:
let x = 1;
let y = 2;
[x,y] = [y,x]
4、如果我们只需要拿3这个变量呢?
let arr = [1,2,3]
let [,,c] = arr
console.log(a)
如果至输入一个a,只会读取到第0个,也就是 1 这个数字。
5、如果有数组嵌套
目标:从下列数组中拿出3
let arr = [1,[2,3,4],5,6]
let [[,a]] = arr
console.log(a)
6、如果有空数组
let [x=1] = []
console.log(x)
如果没有被赋值,那么会得到undefined,这里x被赋予了一个初始的默认值1,那么运行的结果就是1,如果在后期拿到了这个这个数组的值那么就会输出拿到的数组的值。
A-3-2 对对象的解构赋值
let obj ={
name:"whj"
age:100
}
let {age,name} = obj
console.log(name,age)
输出的结果不变,说明在let中的两者的顺序不会影响最后输出的结果;如果只输入age,那么就只会输出100这个值
例2:
let code = "AAA"
let res = {
code:200,
data:"11"
}
let {data,code:co,err="没有错误"} = res;
console.log
//如果data更复杂,例如这个data里有一个列表
let code = "AAA"
let res = {
code:200,
data:{
list:["aaa","bbb","ccc"]
}
}
let {data:{list},code:co,err="没有错误"} = res;//这里需要注意的是这里要一层一层往里写
console.log(list,co,err)//打印需要写最后一层
A-3-3 对函数的解构赋值
function getData(){
let res = {
code:20,
data:{
list:["aaa","bbb","ccc"]
}
}
test(res)
}
function test(res){//我们也可以在接受这个参数的时候就直接进行结构
console.log(res)
let {code,data:{list}}
}
getData()
我们也可以在接受这个参数的时候就直接进行结构:
function getData(){
let res = {
code:20,
data:{
list:["aaa","bbb","ccc"]
}
}
test(res)
}
function test({code,data:{list}}){ //这里
console.log(code,list)
//let {code,data:{list}}
}
getData()
A-3-4 对字符串解构赋值
let myname = "isWHJ"
let [x,y,z] = myname
console.log(x,y,z)
就会取出:i,s,W
let myname = "isWHJ"
let [length] = myname
console.log(length)
//也可以给length取个别名,格式:
//let {length:len} = myname
取出字符串的长度:5
A-4 模板字符串
1、拼接
现在需要我们将li以拼接的方式插入到ul中
以前的方法:
<body>
<ul>
</ul>
<script>
let name = "isWhj"
let oli = "<li>\ //换行必须用反斜杠\连接
<b>"+name+"</b>\ //name用变量来代替就需要用字符串来拼接
</li>"
</script>
</body>
现在的方法:
<body>
<ul>
</ul>
<script>
let name = "isWhj"
let oli = `<li>
<b>${name}</b> //${}是模板字符串的特殊标记语言,会被编译(编译过程就是去掉${},然后用name中的内容替换)
</li>`
console.log(oli)
</script>
</body>
注意:${}
只能出现在模板字符串中
2、插入
后端返回的数组将他们展示成列表显示在页面上
function test(){
return "XXX"
}
let arr = ["aaaaa","bbbbb","ccccc"]
let newlist = arr.map(function(item,index){ //构造map函数
return `<li class="${index===0?'avtive':' '}"> //${}中还可以加三目运算符
<b>${item}</b>
${test()} //${}中还可以放置函数
</li>`
})
console.log(newlist)
let oul = document.querySelector("ul")
oul.innerHTML = newlist.join("") //将逗号改成空格
A-5 扩展
A-5-1 字符串扩展
1、include
函数
判断字符串是否存在指定字符
let myname = "isWhj"
console.log(myname.include("e")) //false,当然也可以是一串,比如Whj
console.log(myname.starsWith("i")) //true 判断这个字符串是否在开头
console.log(myname.endsWith("x")) //false 判断这个字符串是否在结尾
这三个函数都是可以接受函数的
let myname = "isWhj"
//01234 注意0是第一个
//43210 如果判断是否结尾需要从后往前编号
console.log(myname.include("e",2)) //false,这里指从第2个往后开始判断是否存在
console.log(myname.starsWith("s",1)) //true 从第一个位置开始判断这个字符串是否在开头
console.log(myname.endsWith("x",3)) //false 判断这个字符串是否在从后往前数的第3个作为结尾
2、repeat
函数
repeat()
方法返回一个新的字符串,表示将源字符串重复n次
let myname = "isWhj"
console.log(myname.repeat(2)) //isWhjisWhjisWhj
console.log(myname.repeat(0)) //"" 空字符串
console.log(myname.repeat(3.5)) //isWhjisWhjisWhj
console.log(myname.repeat("4")) //重复4次。会自动将字符串转变成数字
A-5-2 数值扩展
1、二进制和八进制表示法
//支持二进制和八进制
let count1 = 100
let count2 = 0x100
let count3 = 0b100
let count4 = 0b100
2、isFinite
和isNaN
的方法
用于减少全局性的方法,是的语言逐步模块化
let num1 = Number.isFinite(100) //true
let num2 = Number.isFinite(100/0) //false
let num3 = Number.isFinite(infinity) //false
let num4 = Number.isFinite("100") //false
let num1 = Number.isNaN(100) //false
let num2 = Number.isNaN(NaN) //true
let num3 = Number.isNaN("whj") //false
let num4 = Number.isNaN("100") //false
他们雨传统的全局方法isFinite()
和isNaN()
的区别在于,传统方法调用Number()
将非数值的值转为数值,再进行判断,而这两个方法只对数值有效,Number.isFinite()
对于非数值一律返回false,Number.isNaN()
只有对于NaN才返回true,非NaN的一律返回false
3、isInteger
方法
用于判断一个数是不是整数
let num1 = Number.isInteger(100) //true
let num2 = Number.isInteger(100.0) //true ,但是100.1就不是整数了
let num3 = Number.isInteger("xxx") //false
let num4 = Number.isInteger("100") //false
4、Number.EPSILON
极小常量
他表示1与大于1的最小浮点数之间的差。2.220446049250313e-16
function isEqual(a,b){
return Math.abs(a-b)<Number.EPSILON
}
console.log(isEqual(0.1+0.2,0.3)) //true
console.log(0.1+0.2===0.3) //false
5、Math.trunc
将小数抹除,返回一个整数
console.log(Math.trunc(1.2)) //1
console.log(Math.trunc(-1.8)) //-1
6、Math.sign
用于判断一个数到底是正数、负数、还是零,对于非数值,会先将其转换为数值在判断
Math.sign(-100) //-1
Math.sign(100) //+1
Math.sign(0) //+0
Math.sign(-0) //-0
Math.sign("xxx") //NaN
A-5-3 数组扩展
1、扩展运算符
不改变原数组的情况下复制
let arr1 = [1,2,3]
let arr2 = [...arr]//这里的三个点指的是将数组的中括号破除,将数组内容放置到这个位置上,当然只能复制1级
arr2.pop() //删除数组最后一个数
console.log([arr1,arr2])
快速合并
let arr1 = [1,2,3]
let arr2 = [4,5,6]
console.log([...arr1,...arr2])
和解构赋值关联
let arr = [1,2,3,4,5,6,7,8]
let [a,b,...c] = arr
console.log(a,b,c) //1,2,[4,5,6,7,8]
2、Array.from
将类数组转换为真正数组
此外arguments
:在没有形参的情况下能拿到所有实参的内容。不要用map等数组方法
function test(){
console.log(Array.from(argument))
}
test(1,2,3,4)
let olis = documents.querySelectorAll("li")
Array.from(olis).map(function(){
})
3、Array.of
将以阻止转化为数组,(重新生成一个数组)
如果我们在Array中只输入一个数字,会默认成一个包含几个内容的数组
例如:
let arr = Array(3)
console.log(arr)
得到:empty x 3
let arr1 = Array(3)
let arr2 = Array.of(3)
console.log(arr1,arr2)
就能得到arr2
为[3]
4、find
和findIndex()
find
找到这个数
let arr = [11,12,13,14,15]
//将>13的数找出来
let res = arr.find(function(item){
return item>13
})
console.log(res)
let arr = [11,12,13,14,15]
//将>13的数找出来
let res = arr.findLast(function(item){ //从后往前搜索
return item>13
})
console.log(res)
findIndex()
找到这个数的索引值
let arr = [11,12,13,14,15]
//将>13的数找出来
let res = arr.findIndex(function(item){
return item>13
})
console.log(res)
let arr = [11,12,13,14,15]
//将>13的数找出来
let res = arr.findLastIndex(function(item){ //从后往前搜索
return item>13
})
console.log(res)
5、fill
填充。初始化数组或者将数组中的一些元素替换
let arr = new Array(3).fill("xxx") //塑造三个空数组,然后每个数组填充入xxx
console.log(arr)
let arr1 = [11,22,33]
console.log(arr1.fill("xxx")) // 将里面的每一项替换
let arr1 = [11,22,33]
console.log(arr1.fill("xxx",1,2)) //从第一项开始,到第二项结束进行替换
6、扁平化
flat()
,flatMap
以前用得较多的是lodash库,但是现在ES6已经自带了这样一个库,所有我们可以直接用。
let aa = [1,2,3,[4,5,6]]
lar arr1 = arr.flat() //将嵌套数组铺开,并且不影响数据
console.log(arr,arr1)
例子:
let arr = [
["安庆","安阳","鞍山"],
["北京","保定","包头"]
]
console.log(arr.flat())
对于复杂的二维数组,我们可以使用flatmap:
let arr = [
{
name:"A",
list:["安庆","安阳","鞍山"]
},
{
name:"B",
list:["北京","保定","包头"]
}
]
let res = arr.flatMap(function(item){
return item.list
})
console.log(res )
A-5-4 对象扩展
1、对象简写
let name = "moduleA"
let obj = {
name, //这样写就等于是name:name
test1(){
},
test2(){
}
}
2、对象属性包含表达式
let name = "a"
let obj = {
[name+"bc"]:"xxx"
}
console.log(obj)
3、扩展运算符 (ES2018支持)
ES9
let obj = {
name:"xxx"
}
//let obj1 = {
// ...obj
// }
let obj2 = {
age:100
}
obj1.name = "vvv"
console.log(...obj1,...obj2) //将两个对象合并在一起,并且不同名称的合并,同名的后者覆盖前者
ES6也有合并数组的方法
Object.assign
方法
let obj1 = {
name:"xxx"
}
let obj2 = {
age:100
}
let obj3 = {
neme:"vvv"
}
console.log(Object.assign(obj1,obj2,obj3))
这个方法的弊端就是会影响到obj1,这个方法的原理是将后面两个加入到obj1中,如果内部有同名就会后者覆盖前者。所以一般会在
4、Object.is
ES6.判断两个值是否相等
曾经的方法:
== 可以判断值
=== 既可以判断值也可以判断类型,但是无法判断NaN是否相等
Object.is
和===
基本相同
console.log(Object.is(5,5));//true
console.log(Object.is(5,"5"));//false
console.log(Object.is({},{}));//false
console.log(Object.is(NaN,NaN));//true
console.log(Object.is(parseInt("xxx"),NaN));
console.log(Object.is(+0,-0)) //false
console.log(+0===-0)//true
A-5-5 函数扩展
1、参数默认值
function ajax(url,method="get",async=true){
console.log(url,method,async)
}
ajax("/aaa","xxx",true)
没有输入值就会输出默认值get,如果后面赋值了如:xxx就会覆盖原默认值
2、rest参数,剩余参数
function test (x,y,...data){
console.log(data)
}
test(1,2,3,4,5,6)
//x=1,y=2,data=3,4,5,6
3、name属性
console.log(test.name)
A-5-6 箭头函数
1:样例
let test = ()=>{
console.log("test")
}
test()
↓
let test = ()=>"11111111"
console.log(test())
实际应用:将li插入到上面html中的ol中
原来的代码script部分:
let arr = ["aaa","bbb","ccc"]
let newarr = arr.map(function(item){
return `<li>${item}</li>`
}
console.log(newarr)
现在的代码
let arr = ["aaa","bbb","ccc"]
let newarr = arr.map((item)=>`<li>${item}</li>`)//如果就只有一句的话可以直接省略return和大括号
console.log(newarr)
此外:如果只有一个参数,可以省略小括号
let arr = ["aaa","bbb","ccc"]
let newarr = arr.map(item=>`<li>${item}</li>`)//一个参数
let newarr2 = arr.map((item,index)=>`<li>${item}-${index}</li>`)//两个参数
console.log(newarr,newarr2)
2、如果返回对象需要注意:
let test2 = ()=>({
name:"xxx",
age:100
})//这里注意需要加一个小括号来说明这是一个整体
console.log(test2())
3、无法访问arguments,无法new
let test3 = ()=>{
console.log(arguments)
}
test(1,2,3,4)
//undefind
let test3 = ()=>{
}
new test3()
//test3 is not a constructor
4、箭头没有this
或者说箭头函数只想父作用域。
案例:模糊搜索
<body>
模糊搜索:
<input type="text" id="mysearch">
<script>
//方法一
// let osearch = document.querySelector("#mysearch")
// osearch.oninput = function(){
// // console.log(this.value)
// let _this = this 保存一个_this来保存this
// setTimeout(function(){
// console.log(_this.value)
// console.log(`发送${_this.value}到后端,获取列表数据`)
// },1000)
// }
//方法二:箭头函数
let osearch = document.querySelector("#mysearch")
osearch.oninput = function(){
setTimeout(()=>{
console.log(this.value)
console.log(`发送${this.value}到后端,获取列表数据`)
},1000)
}
</script>
</body>
简洁了,但是阉割了一些功能
A-6 Symbol
ES6引入了一种新的原始数据类型symbol,表示独一无二的值,它属于JS语言的原生数据类型之一,其他数据类型是:undefined
、null
、Bollean
、String
、Number
、Object
。6种
A-6-1 使用symbol作为对象署名
lat name = symbol()
let age = symbol()
var obj ={
[name]:"xxx",
[age]:100
}
A-6-2 symbol()
函数可以接受一个字符串作为参数,表示对symbol示例的描述,这主要是为了控制台显示,比较容易区分
let name = symbol("name")
let age = symbol("age")
var obj = {
[name]:"xxx",
[age]:
}
console.log(boj)
以下需要注意
A-6-3 不能进行运算
let s1 = Symbol()
let s2 = Symbol()
console.log(s1+s2) //无效执行,而且也无法用于比较
let s1 = Symbol()
let s2 = Symbol()
console.log(s1==s2) //false
A-6-4 显示调用toString()
console.log(s1.toString()+"aaa")
A-6-5 隐式转换Boolean
let s1 = Symbol()
let s2 = Symbol()
if(s1){
console.log("执行")
}
例子:
let obj = {
name:"xxx"
getName() {
console.log(this.name)
}
}
let name = Symbol()
obj[name] = "vvv"
console.log(obj[name]) //vvv
console.log(obj.name) //xxx
这样可以利用symbol来定义一个新的属性,避免冲突。
A-6-6 利用symbol做一个库
//库
let obj = {
name:"vvv",
getName(){
console.log(this.name)
}
}
let name = Symbol()
obj[name] = "xxx"
console.log(obj[name])//调取库内的name
console.log(obj.name)//调取普通obj属性中的name
所以在以后我们作为库的作者的时候也要注意
let name = Symbol()
let age = Symbol()
let obj = {
[name]:"xxx",//因为上面将symbol变成变量,所以这里的name和age都要用[]来括起来
[age]:100,
[Symbol()]:"vvv"//
}
console.log(obj)
我们以后也可以定义一些symbol用作封装的库:
let key = {
name:Symbol(),
age:satisfies(),
location:Symbol(),
test:Symbol()
}
let obj = {
[keys.name]:"xxx",
[kets.age]:100,
[ket.location]:"cz",
[keys.test](){
console.log(test)
}
}
console.log(obj[keys.name])
我们可以利用symbol来传递参数
目的是将一些参数进行区分
let key = {
name:Symbol("name"),
age:satisfies("age"),
location:Symbol("location"),
test:Symbol("test")
}
let obj = {
[keys.name]:"xxx",
[kets.age]:100,
[ket.location]:"cz",
[keys.test](){
console.log(test)
}
}
console.log(obj[keys.name])
但是用了symbol就不能用for和in,也无法用for和in来调出symbol内的属性
当然,也是有方法的:
let key = {
name:Symbol("name"),
age:satisfies("age"),
location:Symbol("location"),
test:Symbol("test")
}
let obj = {
[keys.name]:"xxx",
[kets.age]:100,
[ket.location]:"cz",
[keys.test](){
console.log(test)
}
}
obj.name = "aaa"
console.log(obj[keys.name])
//方式一
console.log(Object.getOwnPropertySymbols(obj))
//方式二
Reflect.ownKeys(obj).forEach(item=>{
console.log(item,obj[item])
})
A-6-7 作为常量
例子:
const VIDEO = Symbol()
const AUDIO = Symbol()
const IMAGE = Symbol()
function play(type){
switch(type){
case VIDEO:
console.log("1")
break;
case AUDIO:
console.log("2")
break;
case IMAGE:
console.log("2")
break;
}
}
play(AUDIO)
这样在play中传参的时候只能是上面const后面的参数,其他参数无法生效
A-7 Iterator迭代器
Iterator的作用有三:
一是为各种数据结构提供一个统一的、简洁的访问接口(Iterator接口);
二是是的数据结构的成员能够按某种次序排列;
三是ES6创造了一种新的便利命令for..of
循环,Iterator接口主要供for..of
循环
数组也支持Iterator接口
A-7-1 for...of
遍历
for of
的遍历和以前的let...in
遍历有三所不同
前者可以拿到数组中的内容,后者只能拿到它的索引值
let arr = ["aaa","bbb","ccc"]
for(let i in arr){
console.log(i)
}//1,2,3
let arr = ["aaa","bbb","ccc"]
for(let i of arr){
console.log(i)
}//aaa,bbb,ccc
for...of
是数组原型上的一个方法
ES6之Symbol详解
迭代器中的next方法
//1迭代器
let arr = ["aaa","bbb","ccc"]
for(let i of arr){
console.log(i)
}
console.log(arr)
let iter = arr[Symbol.iterator]()//2这是迭代器的对象
//console.log(iter) 这里返回的就是遍历器的对象
//3迭代器对象中有个方法就是next
//我们将arr利用next的方法打印:
console.log(iter.next()) //value:'aaa',done:false
console.log(iter.next()) //value:'bbb',done:false
console.log(iter.next()) //value:'ccc',done:false
console.log(iter.next()) //value:undefined,done:true
value是值,done是指是否结束,这个类似于C中的指针或者Java中的迭代器。
Iterator的遍历过程如下:
(1)创建一个指针对象,只想当前数据结构的起始位置。也就是说,遍历器对象本质上就是一个指针对象。
(2)第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。
(3)第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。
(4)不断调用指针对象的next方法,直到它只想数据结构的结束位置。
ES6规定,默认的Iteratol接口部署在数据结构的Symbol.iterato
属性,或者说,一个数据结构只要具有Symbol.iterato
属性,就可以认为是“可遍历的”。
原生默认具备Iterator接口的数据结构如下:
Array
Set
Map
String
Arguments 对象
NodeList 对象
后面两个是伪数组;对象大部分不支持,因为对象是非线性的。
let obj = {
0:"xxx",
1:"vvv",
2:"uuu",
}
for(let i of obj){
console.log(i)
}
报错:这个对象是不可遍历的。
对此,我们可以自己埋一个:
第一类(线性的):
let obj = {
0:"xxx",
1:"vvv",
2:"uuu",
length:3,//设置数组长度
[Symbol.iterator]:Array.prototype[Symbol.iterator]//迭代器
}
for(let i of obj){
console.log(i)
}
第二类:
let obj2 = {
code:200,
name:"obj2",
list:["xxx","vvv","uuu"],
[Symbol.iterator](){
let index = 0
return {
next:()=>{
return {
value:this.list[index++],
done:index===this.list.length+1?true:false
}
}
}
}//这里形成一个闭包
}
//上面就是迭代器
let iter = obj2[Symbol.iterator]()
console.log(iter)
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
这个看起来可以用迭代器
注意:对象的三点解构赋值用的不是迭代器
A-7-2 如何对于对象进行For of
遍历?
let str = "Remarkable"
for(let i of str){
console.log(i)
}
这里的出来的就是Remarkable的各个字母
三点展开运算符会默认使用其内部的
let obj2 = {
code:200,
name:"obj2",
list:["xxx","vvv","uuu"],
[Symbol.iterator](){
let index = 0
return {
next:()=>{
return {
value:this.list[index++],
done:index===this.list.length+1?true:false
}
}
}
}
}
// for(let i of obj2){
// console.log(i)
// }
let iter = obj2[Symbol.iterator]()
console.log(iter)
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
console.log([..obj2])
let oli = document.querySelectorAll("li")
console.log([...oli])//会自动将我们迭代器中的内容展开变成数组
//不过我们之前学的Array也可以将oli展开成数组形式
console.log(Array.from(oli))
A-8 Set结构
它类似于数组,单成员的值都是唯一的,没有重复的值。
A-8-1 初识Set
Set的书写方式有两种,分别如下:
方案一
let s1 = new Set([1,2,3,2,3,4])
console.log(s1)
//1,2,3,4
console.log([...s1])
//[1,2,3,4]
console.log(Array.from(s1))
//[1,2,3,4]
方案二:
let s2 = new Set()
s2.add(1)
s2.add(2)
s2.add(2)
s2.add(3)
console.log(s2)
然后我们就可以利用这个特性进行for...of
遍历
A-8-2 Set的属性和方法
size属性
这是set的唯一一个属性,用于输出该Set数组的长度
let s1 = new Set([1,2,3,2,3,4])
console.log(s1)
console.log([...s1])
console.log(Array.from(s1))
let s2 = new Set()
s2.add(1)
s2.add(2)
s2.add(2)
s2.add(3)
console.log(s2)
//set唯一属性:
console.log(s1.size)
方法1: add
向原数组中添加内容
let s1 = new Set([1,2,3,2,3,4])
console.log(s1)
console.log([...s1])
console.log(Array.from(s1))
let s2 = new Set()
s2.add(1)
s2.add(2)
s2.add(2)
s2.add(3)
console.log(s2)
//set唯一属性:
console.log(s1.size)
//add
s1.add(5).add(6)
console.log(s1)
方法2: has
has用于检测set数组中是否含有该内容,返回布尔值,表示该值是否伪Set成员
let s1 = new Set([1,2,3,2,3,4])
console.log(s1)
console.log([...s1])
console.log(Array.from(s1))
let s2 = new Set()
s2.add(1)
s2.add(2)
s2.add(2)
s2.add(3)
console.log(s2)
//set唯一属性:
console.log(s1.size)
//add
s1.add(5).add(6)
console.log(s1)
//has
console.log(s1.has(5))//true,因为上面添加了
方法3: delete
删除内容,返回一个布尔值,表示删除是否成功
let s1 = new Set([1,2,3,2,3,4])
console.log(s1)
console.log([...s1])
console.log(Array.from(s1))
let s2 = new Set()
s2.add(1)
s2.add(2)
s2.add(2)
s2.add(3)
console.log(s2)
//set唯一属性:
console.log(s1.size)
//add
s1.add(5).add(6)
console.log(s1)
//has
console.log(s1.has(5))//true,因为上面添加了
//delete
s1.delete(5)
console.log(s1.has(5)) //false
方法4:clear
清楚数组内容,没有返回值(不做演示)
A-8-3 遍历
1、2、3为for…of遍历,4为forEach遍历
以下第一点和第二点效果一样
1、Set.prototype.keys()
:返回键名的遍历器
返回值和内容一样
let s2 = new Set()
s2.add(1)
s2.add(2)
s2.add(2)
s2.add(3)
console.log(s2)
for(let i of s2.keys()){
console.log(i)
}
//1
//2
//3
2、Set.prototype.values()
:返回键值(value)的遍历器
let s2 = new Set()
s2.add(1)
s2.add(2)
s2.add(2)
s2.add(3)
console.log(s2)
for(let i of s2.values()){
console.log(i)
}
//1
//2
//3
注意:1和2还有什么都不加的效果一样,都是返回Set对应的内容
3、Set.prototype.entries()
:同时返回键值和键名的遍历器
键值和键名以数组的形式返回。也许在Set中没什么用,但是可以在以前学的数组中使用(也可以搭配解构使用):
//对于Set
let s2 = new Set()
s2.add(1)
s2.add(2)
s2.add(2)
s2.add(3)
console.log(s2)
for(let i of s2.entries()){
console.log(i)
}
//对于数组
let arr = ["aa","bb","cc"]
for(let [index.item]of arr.entries()){
console.log(i)
}
4、Set.prototype.forEach()
:遍历每个成员
s2.forEach((item,index)=>{
console.log(item,index)
})
A-8-4 利用Set去重的案例
现给出一个复杂的数组,利用所学知识封装一个函数进行去重。
let list = [1,2,2,"xxx","xxx",[1,2],[3,4],[1,2],{name:"xxx"},{age:100},{name:"xxx"},undefined,NaN,undefined,NaN]
//解答如下
function uni(arr){
let res = new Set()
return arr.filter((itm)=>{
//利用has判断,如果有则返回false
//如果没有,就返回true
let id = JSON.stringify(item)//将数组转化为字符串
if(res.has(id)){
return false
}else{
res.add(id) //如果没有的话需要我们自己将内容添加进去
return true
}
})
}
A-9 Map结构
类似于对象,也是键值对的集合,但是”键“的范围不限于字符串,各种类型的值(包括对象)也可以当作键。
用法一:
let m1 = new Map([
["name","xxx"],
["age",100],
[{a:1},"江苏"]
])
console.log(m1)
这里的箭头不是指箭头函数,而是对应的分别为key和value
用法二:
先定义一个空map,然后慢慢往里面加
let m2 = new Map()
m2.set("name","xxx")
m2.set("age",100)
m2.set({a:1},"江苏")
console.log(m2)
Map内置迭代器
let m2 = new Map()
m2.set("name","xxx")
m2.set("age",100)
m2.set({a:0},"江苏")
console.log(m2)
for(let i of m2){
console.log(i)
}
console.log([...m2])
A-9-1 Map方法
1、get
let o = {a:1}//需要我们在上面先设置一个地址,才能get到下面m2
let m2 = new Map()
m2.set("name","xxx")
m2.set("age",100)
m2.set(o,"江苏")
console.log(m2.get(o))//江苏
2、delete
let o = {a:1}
let m2 = new Map()
m2.set("name","xxx")
m2.set("age",100)
m2.set(o,"江苏")
m2.delete("age")
3、has
let o = {a:1}
let m2 = new Map()
m2.set("name","xxx")
m2.set("age",100)
m2.set(o,"江苏")
console.log(m2.has("age"))//true
4、size
let o = {a:1}
let m2 = new Map()
m2.set("name","xxx")
m2.set("age",100)
m2.set(o,"江苏")
console.log(m2.size)//3
5、clear
let o = {a:1}
let m2 = new Map()
m2.set("name","xxx")
m2.set("age",100)
m2.set(o,"江苏")
m2.clear()
console.log(m2)
Map和Set一样也有keys()
、values()
、entries()
、for...of
、forEach
一样的方法,名字和写法也一样
A-10 Proxy代理
proxy如其名,他的作用是在对象和对象的属性值之间设置一个代理,获取该对象的值或者设置该对象的值,以及实例化等等多种操作,都会被拦截住,经过这一层我们可以同一处理,我们可以认为他就是“代理器”
这是在后续的响应式布局的一种原理
在ES5中,我们拦截数据所用的方法是Object.defineProperty()
,括号里含三个参数,分别为:要被修改(拦截)的对象,要被修改(拦截)的属性和get、set的回调
例子代码:
<body>
<div id = box></div>
</body>
<script>
let obj = {}
console.log(box)
Object.defineProperty(obj,"data",{
get(){
console.log("get")
return box.innerHTML//get一定要返回
},
set(value){
console.log("set")
//设置dom
box.innerHTML = value
}
})
console.log(obj)
</script>
缺点:1、每一次只能拦截一个属性,2、只能拦截对象,如果是用数组就做不到
而proxy就相当于给对象添加一个代理,然后将来就可以对代理进行修改