11-Iterator迭代器
- 打印出的是里面的内容,如果是for in打印出来的是索引,of不能遍历对象
- Symbol.iterator是js内置的,可以访问直接对象arr[Symbol.iterator],()调用
- 对象非线性一般不能迭代
后两个是伪数组,但是是真迭代器接口
...解构赋值
...展开运算符默认会调用内置迭代器,自动转换为数组形式
12-set结构
- 类似于数组,但成员的值都是唯一的,没有重复
- 与数组不同的是set没有索引
let s1=new Set([1,2,3,4,2,1])
console.log(s1);
console.log([...s1]);//...展开运算符默认会调用内置迭代器,自动转换为数组形式
console.log(Array.from(s1));//将类似于数组的内容转化为真数组
set结构键名和键值相同,放进一个数组[11 ,11][22,22][33,33]
for(let i of s2.entries()){
console.log(i);
}
set结构没有索引只有一个值,因此结果是11 11;22 22;33 33
s2.forEach((item,index)=>{
console.log(item,index);
})
// 数组也可以用entries
// let arr=["aa","bb","cc"]
// for(let i of arr.entries()){
// console.log(i);//打印出来是索引和值组成的数组
// }
let arr=["aa","bb","cc"]
for(let [index,item] of arr.entries()){
console.log([index,item]);
}//[0,11][1,22][2,33]
面试题:给一个数组去重
思路:把数组里面的item都转换为字符串(因为set无法区分对象),再送到set里面进行判断有没有
arr. filter()方法里面的函数返回false会清除该数据,true会保留
let list=[1,2,2,"kerwin","kerwin",[1,2],[3,4],[1,2],
{name:"kerwin"},{age:100},{name:"kerwin"},undefined,undefined];
function uni(arr){
let res=new Set();
return arr.filter(item=>{
let id=JSON.stringify(item);
if(res.has(id)){
return false;
}else{
res.add(id);
return true;
}
})
}
console.log(uni(list));
13-Map结构
类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
内置Iterator迭代器对象(用for of遍历比普通对象便利)
let o={a:1}
let m2=new Map();
m2.set("name","kerwin");
m2.set("age",100);
m2.set(o,"大连");
console.log(m2);
for(let i of m2){
console.log(i);
}
console.log([...m2]);//里面得到的是数组形式
// set get has delete size clear
console.log(m1.get({a:1}));//两个对象地址不一样,undefined拿不到m2里面的值
console.log(m2.get(o));//大连
keys() values() entries() 返回的都是一个迭代器 用for of遍历,foreach
for(let i of m1.values()){
console.log(i);
}
for(let i of m1.entries()){
console.log(i);
}
for(let [index,item] of m1.entries()){
console.log([index,item]);
}
for(let [index,item] of m1){
console.log([index,item]);
}
console.log("======");
m1.forEach((item,index)=>{
console.log(item,index);
})
14-Proxy代理
Proxy的作用是在对象和和对象的属性值之间设置一个代理,获取或设置该对象的值,以及实例化等多种操作,都会被拦截住,经过这一层我们可以统一处理,我们可以认为它就是”代理器”
let s=new Set();
// 只能修改代理proxy才能修改s
// 代理拥有代理对象的所有东西
let proxy=new Proxy(s,{
// 方法内部用到了this,this应该指向实例化对象,但用了proxy代理后指向了proxy,
// 因此报错需要修改this指向(也就是set里找自带方法才能去调用add()什么的)
get(target,key){
let value=target[key]
// 判断value是不是一个方法(instanceof用于判断左边的对象是不是右边的类的实例)
if(value instanceof Function){
// 用于修正的方法:call apply bind前两个在修正的时候就手就调用了,而bind不会
// call() apply() bind()括号里填修正的指针指向谁
return value.bind(target);// target就是Set对象因此填写target
}
// get必须要返回东西
return value
},
set(target,key,value){
console.log("set",target,key,value);//{},name,"kerwin"
if(key=="date"){
box.innerHTML=value;
}
target[key]=value;
}
})
proxy本质上属于元编程非破坏性数据劫持,在原对象基础上进行了功能的衍生而又不影响对象
15-Reflect
Reflect可以用于获取目标对象的行为,它与Object类似,但是更易读,为操作对象提供了一种更优雅的方式。它的方法与Proxy是对应的。
1.代替object的某些方法
2.修改某些object的方法返回结果
3.命令式变为函数行为
get,set方法
let obj = {
name:"kerwin"
}
Reflect.set(obj,"age",100)
Reflect.get(obj,"name")
4.配合proxy使用:
let s=new Set();
let proxy=new Proxy(s,{
get(target,key){
// let value=target[key]
let value=Reflect.get(target,key)
// 判断value是不是一个方法(instanceof用于判断左边的对象是不是右边的类的实例)
if(value instanceof Function){
// 用于修正的方法:call apply bind前两个在修正的时候就手就调用了,而bind不会
// call() apply() bind()括号里填修正的指针指向谁
return value.bind(target);// target就是Set对象因此填写target
}
// get必须要返回东西
return value
},
set(target,key,value){
// Reflect.set(target,key,value)
Reflect.set(...arguments)//如果是一个数组,用...展开传进去
}
})
16-Promise对象
promise是异步编程的一种解决方案,比传统的解决方案回调函数更合理和更强大。
1.使用:
// 执行器函数
let pro=new Promise(function(resolve,reject){
setTimeout(()=>{
// resolve(1000)
reject("no 1111")
},1000)
})
// pro.then(()=>{
// // 成功
// console.log("奖金");
// },()=>{
// // 失败
// console.log("没有");
// })
pro.then((res)=>{
// 成功的函数
console.log("奖金",res);
}).catch((err)=>{
// 失败的函数
// 捕获错误
console.log("没有",err);
})
2.Promise对象的状态(
- Promise对象通过自身的状态,来控制异步操作。Promise实例具有三种状态:
异步操作未完成(pending)
异步操作成功(fulfilled
)
异步操作失败(rejected
) - 这三种的状态的变化途径只有两种。
从“未完成”到“成功”
从“未完成”到“失败” 一旦状态发生变化,就不会再有新的状态变化。
这也是Promise这个名字的由来,它的英语意思是“承诺”,一旦承诺成效,就不得再改变了。这也意味着,Promise实例的状态变化只可能发生一次
。
因此,Promise的最终结果只有两种:
异步操作成功,Promise实例传回一个值(value),状态变为fulfi1led。
异步操作失败,Promise实例拋出一个错误(error),状态变为rejected。
3. .then.then链式调用
看第一个.then返回的结果,如果是非promise对象,会自动转换为fulfilled对象。
如果是,根据这个新的promise对象决定下一步是resolve执行then还是reject执行catch
4.promise方法:all,race
- Promise.all():里面的几个都成功了才走.then,只要有一个失败就走.catch
·[pro1,pro2,pro3]数组里面的一起执行 - Promise.race(),谁先回来就执行谁相应的状态指定的回调函数
应用场景:超时处理(pro1,pro2其中一个如果执行不了就返回超时)
17-Generator生成器函数
返回值就是一个遍历器
yield表达式返回值取决于下一个next()方法中传入的参数
<script>
// 协程让函数暂停执行,需要调用next()才能往下走
function* gen() {
console.log(11);
yield "aa"; //中文产出的意思
console.log(22);
yield "bb";
console.log(33);
//如果是return "cc"不会被遍历出来,打印出来value是“cc”,done已经变成true了,是true时就停了
}
let g=gen()
// g.next()//11
// g.next()//22
// g.next()//33
let res1=g.next()
console.log(res1);
let res2=g.next()
console.log(res2);
let res3=g.next()
console.log(res3);
//for(let i of g){
// console.log(i);
//}可以一下子遍历完
</script>
结果不会有”-11111“(还没有给res1赋值就遇到yield停止了)
18-Class语法
1.类的写法
2.getter与setter拦截属性
不能在location里面拦截后再操作自己的属性,会进入一个死循环的递归调用
class Person{
constructor(name,age,id){
this.name=name;
this.age=age;
this.ele=document.querySelector(`#${id}`);
}
get location(){
console.log("get");
}
set location(data){
console.log("set",data);
}
get html(){
return this.ele.innerHTML
}
set html(data){
this.ele.innerHTML=data.map(item=>`<li>${item}</li>`).join("")
}
}
let obj=new Person("kerwin",100,list)
obj.html=["111","222","333"]
// 在控制台赋值obj.html=["111","222","333"]时候会被set拦截到,它基于html把数据映射成li节点
class Person{
// 如果希望一个属性是静态的可以在前面加一个static
static myname="person类的名字";
static mymethod=function(){
// console.log("mymethod",this.age);在这里访问不到age,因为this指向的是Person的类名,不是实例化对象
}
constructor(name,age,id){
this.name=name;
this.age=age;
}
say(){
console.log(this.name,this.age);
}
}
Person.myname="person类的名字"
Person.mymethod=function(){
console.log("mymethod");
}
let obj=new Person("kerwin",100)
// 访问,在控制台obj.myname访问不到,
//应用场景:有些属性或方法不需要实例化对象就可以挂在类的身上(称为静态属性和静态方法),比如person都会的事
// console.log(Person.myname);
// Person.mymethod()
3.Class继承
1.super()方法继承调用父类constructor里面的方法
2.如果和父类方法名一样会就近原则执行,执行自己的覆盖父类,包括静态属性和静态方法
3.如果想在父级相同的方法基础上添加一些操作,需要调用super
class Student extends Person{
constructor(name,age,score){
super(name,age)
this.score=score;
}
2.如果和父类方法名一样会就近原则执行,执行自己的覆盖父类
// say(){
// console.log(this.name,this.age,this.score);
// }
3. 如果想在父级相同的方法基础上添加一些操作,需要调用super
say(){
super.say();//调用父级的say方法
console.log(this.score);
}
getScore(){
console.log(this.score);
}
}
let obj=new Student("kerwin",100,150)
案例:用面向对象的思路将数据传给box
<div class="box1">
<h1></h1>
<ul></ul>
</div><div class="box2">
<h1></h1>
<img src="" alt="">
<ul></ul>
</div>
<script>
var data1={
title:"体育",
list:["体育1","体育2","体育3"]
}
var data2={
title:"综艺",
url:"https//................................",
list:["综艺1","综艺2","综艺3"]
}
class CreatBox{
// 获取节点和数据
constructor(select,data){
this.ele=document.querySelector(select)
this.title=data.title;
this.list=data.list;
// 初始化完后立即执行渲染页面
this.render()
}
render(){
let oh1=this.ele.querySelector("h1")
let oul=this.ele.querySelector("ul")
oh1.innerHTML=this.title
oul.innerHTML=this.list.map(item=>`<li>${item}</li>`).join("")
}
}
class CreatImgBox extends CreatImgBox{
constructor(select,data){
super(select,data)
this.imgUrl=data.url
this.render()//再调用一遍(防止子类中的某些操作执行不到而出错)
}
render(){
super.render()
let oimg=this.ele.querySelector("img")
oimg.src=this.imgUrl
}
}
new CreatBox(".box1",data1)
new CreatImgBox(".box2",data2)
</script>
19-Module模块化
好处:异步加载、 私密不漏、 重名不怕(不同js包下面方法名相同的)、依赖不乱
defer,async异步加载 不会被script标签阻塞,会继续往下面走
<script src="20-Module.js" defer></script>一直等到全部渲染完后才去执行
<script src="20-Module.js" async></script>一旦下载完渲染引擎就会中断渲染
<script src="20-1.js" type="module"></script>这种方式引入js会访问不到里面的方法
私密不漏引用方法1:
在哪用在哪引
1.在js里导出方法
// const obj={
// A1,
// A2
// }
// export default obj
export default {
}
2.在script里导入js中的方法
<body>
<script type="module">
// 导入js中的方法,A1的名称可以改变,from后的链接必须加'./'
import A1 from './20-1.js'
</script>
</body>
重名问题解决:
import obj1 from './20-1.js'
import obj2 from './20-1.js'
console.log(obj1.test(),obj2.test())//重名不怕
导入写法2:
不加default,不能改名(这种写法区别于解构)
export {
A1,
A2
}
import {A1,A2} from './20-1.js'
重名问题解决:as表示重命名后
import {A1,A2,test as testA} from './20-1.js'
import {test as testB} from './20-2.js'
如果想一起导
import * as obj1 from './20-1.js'
import * as obj2 from './20-2.js'
导入写法3:直接在方法前加export
**写法4:**混合使用
20-NodeJS中的模块化