es6-基础知识汇总

​​​​​​​​​​​​​​

目录

一、简介

二、配置babel环境

三、变量声明关键字let、const

var的缺点

 let&const

四、Symbol数据类型  

symbol()、symbol.for

五、解构赋值

什么是解构赋值?

使用解构赋值的前提

使用

六、字符串的扩展方法及模板字符串

七、ES6和ES7之数组的扩展方法及扩展运算符的使用

 八、map & reduce

九、对象中扩展运算符的使用

安装es8 插件

使用

十、Map与WeakMap结构的特点

map 数据类型

WeakMap

遍历方法 for each

十一、Set与WeakSet结构的特点

Set

最大的使用场景:数组去重

 WeakSet  

十二、数组、对象、map、set 增删改查

十三、类型转换

十四、ES6中的代理Proxy和反射Reflect

Proxy

Reflect

一个小案例

十五、rest

十六、箭头函数

js中什么时候使用箭头函数?

十七、类的概念&类的封装及继承

十八、静态方法

十九、import和export

二十、什么是异步编程及js的异步实现

二十一、 Promise

回调地狱

Promise改造回调函数

使用catch方法捕获错误

Promise.all 方法

二十二、interator 方法

二十三、Generator

应用场景

二十四、async(必须搭配await用)


一、简介

ECMAScript(简称ES6),是JavaScrit语言的下一代标准,它的目标是使JavaScript语言可以用来编写复杂的大型应用程序,成为企业级开发语言。

二、配置babel环境

因为浏览器不识别ES6,所以要转换为ES5。

①安装node 下载并安装node.js(npm淘宝镜像、nodemon)

②在vscode中选择文件夹,打开终端输入

npm init -y

③ 输入

npm install --save-dev babel-cli babel-preset-es2015

④ 创建文件    .babelrc  (注意一定要有点!)并输入

/ 配置用于转化当前代码的规则集
{
    "presets": [
        "es2015"
    ]

⑤ 创建项目录,src用于存放编写的es6代码,dist目录用于存放由es6转化后的代码

⑥ 将es6 代码转化为es5

                 ⇨单独转一个文件   node_modules/.bin/babel src/test.js --out-file dist/test.js

                 ⇨转整个文件夹     node_modules/.bin/babel src  --out-dir dist

借助 node_modules/.bin/babel 将src下的src/test.js 转换到dist/test.js(dist下的js不是自己创建  的,是转化过来的)

⑦配置package.json文件 (为了自动转换)操作如下方截图

 //配置监听脚本 一旦src下的js发生变化 自动转化到dist中
"dev":"babel src -w -d dist"

⑧ 用法 在终端输入      注意:dev是一个名字,根据脚本写的

npm run dev

⑨创建index.html文件,输入 

<script src="./dist/test.js"></script>

三、变量声明关键字let、const

var的缺点

存在变量提升;同一作用域下可以重复声明;不存在块级作用域,只存在全局作用域和局部函数作用域;不可以限制修改,只能声明变量不能声明固定值的常量

(1)存在变量提升

console.log(a); //输出undefined
var a = 1
 
// 实际上 变量提升
var a;
console.log(a);
a=1;

(2)同一作用域下可以重复声明

var a = 1;
 
var a = 2;
 
console.log(a) //输出2,可以重复声明,但是在java中会报错

(3)不存在块级作用域,只存在全局作用域和局部函数作用域

(4)不可以限制修改,只能声明变量不能声明固定值的常量

 let&const

  • let

       特点: (1)只在声明的代码块内有效(块级作用域)

                (2)在同一作用域内不允许重复声明

                (3)没有变量提升

                (4)暂时性死区(必须先声明在使用,在变量声明之前,无法读取或者操作这个)

  •  const

       const 用于声明常量 ,只是保证里面的内存地址不变(简单数据类型 如字符串,数字,布尔类型的值,值就保存在变量指向的内容地址,而复杂数据类型 的数据 如对象,数组和函数的时候,变量指向的内存地址,实际上是保存了指向实际数据的指针,所以const只能保证指针是固定的,至于指针指向的数据结构变不变就无法控制了) 

      特点:跟 let 一样

四、Symbol数据类型  

symbol是一种基本数据类型(primitivedatatype)。Symbol()函数会返回symbol类型的值,该类型具有静态属性和静态方法。它的静态属性会暴露几个内建的成员对象;它的静态方法会暴露全局的symbol注册,且类似于内建对象类,但作为构造函数来说它并不完整,因为它不支持语法:"newSymbol(()"

symbol()、symbol.for

每个从symbol()返回的symbol值都是唯一的,即使名字相同

1.Symbol是新增的一种数据类型,表示一种独一无二的(任意两个Symbol类型都是不相等的)

 Symbol相等与否与Symbol()内描述信息没有关系!!!

参数a1相当于对当前Symbol进行备注,用来描述当前这个Symbol
let a1=Symbol("a1");
let a2=Symbol("a1");
console.log(a1);
console.log(typeof a1);
console.log(a1 === a2);

 2.Symbol函数可以接受一个字符串作为参数,表示对该Symbol实例的描述,比较容易区分

const sym1 = Symbol("name")
const sym2 = Symbol("address")
console.log(sym1)
console.log(sym2)
console.log(sym1 === sym1)

const sym1 = Symbol("name")
const sym2 = Symbol("name")
console.log(sym1)
console.log(sym2)
console.log(sym1 === sym2)

 3.应用场景: Symbol作为对象的key

let obj={
    [a1]:123,
    aa:123,
    a1:457
}
console.log(obj);
 
let obj2={}
    obj2[a1]=3;

 4.如果描述信息一样,想得到两个一样的Symbol()值,可以使用Symbol.for()

Symbol.for 这个API代表会在全局寻找叫做aa的这个变量,如果有就会把当前这个symbol赋值到a1变量中,如果没有就会创建symbol再赋值


let a1=Symbol.for("aa");
let a2=Symbol.for("aa");
console.log(a1===a2);

6.为对象赋值的另一种方式:参数1是对象的名称 参数2是key的名称  参数3是当前这个key的值

结合上方代码看
Object.defineProperty(obj,a1,{value:890})

 

7. Symbol的另外一个作用:声明字符串常量,下面代码中的hahaha这个字符串就为常量 

const user=Symbol("hahaha");
console.log(user);

 

8.Object.getOwnPropertySymbol()是用来专门获取指定对象的所有Symbol属性名的

  变量作为对象的属性的时候,通过方括号将变量转换为属性

const key1 = Symbol("hi")
 
const key2 = Symbol("flag")
 
const o = {
 
a:1,   b:2,
 
[key1]: 2022, [key2]:"暴富"  }
 
console.log(o[key1],o[key2])

五、解构赋值

什么是解构赋值?

  • 解构赋值可以理解为赋值操作的语法糖,它是针对数组或者对象进行模式匹配,然后对其中的变量进行赋值,代码书写上言简意赅,语义明确,也方便了对象数据的读取操作 

使用解构赋值的前提

  • ES6中在某种数据上只要有一个遍历接口(数组、字符串、对象),也就说这个数据能够循环遍历的话,就可以进行解构赋值
  • 解构赋值必须:赋值符号左右两边的结构必须一致(要么都是数组,要么都是对象);变量的声明和赋值必须在一句话内完成

使用

① 如果赋值时变量的个数和值的数对应不上,多出来的变量中的值就是undefined

{
    // 如果赋值时变量的个数和值的个数对应不上,多出来的变量中的值就是undefined
    let a, b, c
    [a, b, c, d] = [1, 2, 3];
    console.log(a, b, c, d);
}

②  指定默认值

{
    // 指定默认值
    let a, b, c
    [a, b, c = 9] = [1, 2]
    console.log(a, b, c);
}

③ ...为ES6中的扩展运算符,这样会将a赋值给1,而other会作为一个数据将剩余的值作为整个数组中的元素进行存储

{
    // ...为ES6中的扩展运算符 这样会将a赋值为1,而other会作为一个数组将剩余的值作为整个数组中的元素进行存储
    let a ,other
    [a,...other]=[1,2,3]
    console.log(a,other);
}

 ④  只读取第一个和第三个值,逗号只作为占位符

{
    // 只取第一个和第三个值,逗号只作为占位符
    let a,b 
    [a,,b]=[1,2,3];
    console.log(a,b);
}

⑤   对象解构赋值,如果当前行中的第一个字符为大括号的会报错,所以需要加上小括号

{
    // 对象解构赋值  如果当前行的中的第一个字符为大括号的话会报错,所以需要加上小括号
    let a,  b; 
    ({a,b}={a:2,b:3})
    console.log(a,b);
}

⑥ 只使用属性值不使用属性名,相当于给原有对象中的属性名重新命名

{
    // 只使用属性值不使用属性名,相当于给原有对象中的属性名重新命名
    let num,total;
    ({a:num,b:total}={a:2,b:3})
    console.log(num,total);
}

六、字符串的扩展方法及模板字符串

① 在 es5 中显示乱码  es6 中显示汉字            ⇨ \uxxxx  限制范围:\u0000-\uFFFF

    es6的方案:将超过两个字节的组成字符的码点放在一对大括号里,就可以正确的识别了

{
    // es5                     \uxxxx  限制范围:\u0000-\uFFFF
    const str="\u20bb7";
    console.log(str);
}
{
    // es6的方案:将超过两个字节的组成字符的码点放在一对大括号里,就可以正确的识别了
    const str="\u{20bb7}"
    console.log("es6",str); 

}

② for of:传统for循环无法处理超出范围的字符的,而for of能够正确的处理,处理字符串循环时推荐使用for of进行处理

{
    // for...of: 传统for循环无法处理超出范围的字符的,而 for..of 能够正确的处理,处理字符串循环时推荐使用for of进行处理
    const str="\u{20bb7}"
    for( let i=0;i<str.length;i++){
        console.log(str[i]);
    }
    for(let word of str){
        console.log("for-of",word);
    }
}

③ str.includes() 判断字符串中是否包含指定字符串,返回值是布尔值

{
    // str.includes()   判断字符串中是否包含指定字符串,返回值是布尔值
    let str="123abc321";
    console.log("includes",str.includes("abc"));
}

 ④ str.startsWith() 判断以什么开头的,参数2是从指定的位置数起

{
    // str.startsWith() 判断以什么开头的,参数2是从指定的位置数起
    let str="123abc321";
    console.log("startsWith",str.startsWith("abc",3));
    console.log("endsWith",str.endsWith("abc",6));
}

⑤repeat() 方法  返回一个新字符串,表示将原字符串重复n次

{
    // repeat() 方法返回一个新字符串,表示将原字符串重复n次
    let str="1abc23";
    let str2=str.repeat(3);
    console.log(str);
    console.log(str2);
}

 ⑥ 头部补全  参数1:补全之后的字符串长度 。参数2: 作为补位的字符串,如果超出补全长度自动截取

{
    // 头部补全 参数1:补全之后的字符串长度 。参数2: 作为补位的字符串,如果超出补全长度自动截取
    let str="Apple"
    str=str.padStart(7,"abc");
    console.log(str);

    // 尾部补全 
}

⑦ 模板字符串(反引号-tab按键上面那个``,可以换行,可以加入${变量}解析变量里面的值

{
    // 模板字符串(反引号-tab按键上面那个`,可以换行,可以加入${变量}解析变量里面的值)
    const name="神经质土豆";
    const age=20;
    const str="我叫:"+name+",今年"+age+"岁了"
    console.log(str);
    const str2=` 我叫 ${name}
    我今年${age}岁了
    `
    console.log(str2);
}

七、ES6和ES7之数组的扩展方法及扩展运算符的使用

①扩展运算符 ...

   如果使用arr1=arr2这种方式的话,只是将arr1中存放的地址值赋值给了arr2,这样如果arr1中的数组改变的话,arr2也会跟着改变

   arr1 和 arr2 相互独立,互不影响

{
    // 扩展运算符 ...   复制
    // 如果使用arr1=arr2这种方式的话,只是将arr1中存放的地址值赋值给了arr2,这样如果arr1中的数组改变的话,arr2也会跟着改变
    const arr1=[1,2,3,4,5];
    // let arr2=arr1;
    let arr2={...arr1};
    arr1.push(6);
    console.log(arr2);
    //arr1 和 arr2 相互独立,互不影响

    // 分割数组 用逗号 占位
    const totalArr=[1,"a","b","c"];
    let[,...strArr]=totalArr;
    console.log(strArr);

    // 给函数传参
    function add(x,y){
        return x+y;
    }
    let arr=[4,5];
    console.log(add(...arr));
}

 ② fill替换数组中的元素    ⇨ 参数1:要替换后的值 参数2:开始下标 参数3:结束下标

{
    const list = [1,2,3,4,5];
    //将数组中的元素全部替换为3 原来的数组也发生变化了
    // let list2 = list.fill(3);
    let list2 = [...list].fill(3);
    console.log(list,list2);
    //将数组中的下标为 1 的元素到下标为 4 之前的元素中的值替换成3
    //参数1:要替换后的值 参数2:开始下标 参数3:结束下标
    let list3 = [...list].fill(3,1,4);
    console.log(list3);
}

 

 ③find & findindex  

{
    // find findindex
    const list=[{title:'es6'},{title:'webpack',id:2},{title:'vue'},{title:'webpack',id:3}]
    // find :循环遍历数组,根据条件返回对应的这条数据
    // 回调函数中的item代表数组中的每个元素(arr[i]) 
    let result=list.find(function(item){
            return item.title==="webpack"
    })
    console.log(result);


    let resultIndex=list.findIndex(function(item){
            return item.title==="webpack"
    })
    console.log(resultIndex);//返回对应的索引
}

 ④ Includes & indexOf 

     Includes 判断当前元素是否存在,返回值为布尔类型  ; indexOf返回的是索引或者-1

{
    // Includes 和 indexOf
    // Includes 判断当前元素是否存在,返回值为布尔类型   indexOf返回的是索引或者-1
    const arr=[1,2,3,4,5,6];
    let result=arr.includes(2);
    let result2=arr.indexOf(2);
    console.log(result);
    console.log(result2);
}

 ⑤ flat展开数组

     flat (数字可以表示多展开几层),contact只能到第二层

{
    // flat 展开数组
    const list=[1,2,3,['2nd',4,5,6,['3rd',7,8]]];
    let flatList=list.flat(2);//2 的意思是展开2次
    console.log("flat", flatList);

    let  flatList2=[].concat(...list) //concat 拼接数组,向空数组中拼接复制过来的list数组
    console.log( flatList2);

}

  

⑥Array.from 类数组对象 有length,可以遍历

{
    // Array.from 类数组对象 有length,可以遍历
    const str="hello";
    const arr=Array.from(str);
    console.log(arr);
}

 八、map & reduce

① map 数据映射

   把数组中的 0 ,1 映射成文字

{
    // map 数据映射
    const json=[{name:'张三',gender:0},{name:'李四',gender:1},{name:'小花',gender:1},{name:'小明',gender:0}] 
    let arr=json.map(function(item){
        return {
            name:item.name,
            genderTxt:item.gender ? "女":"男" //判断item.gender是0还是1,0 代表false 选择后面 ;1代表true 选择前面,
        }

        item.gender=item.gender? "女":"男"
        return item

        let obj={};
        // 复制对象
        Object.assign(obj,item);
        obj.gender=obj.gender? "女":"男"
        return obj

    })
    console.log(arr,json);
}

 

 ② reduce 对数组中的每个元素进行一次回调

      reduce(callback,initalValue)

  •  initalValue:是一个返回值 它是一个可选参数,如果传入值的话,callback里面的参数acc的初始值就是这个传入的  值,如果不传入的话acc初始值就是数组中的第一个元素
  • callback:回调函数 callback里面的参数

             acc:返回值(每次回调之后的返回值)

             currentValue:当前进行回掉的值

             currentIndex:当前回调的值对应的索引

{
    /* 
    reduce 对数组中的每个元素进行一次回调
    reduce(callback,initalValue)
        initalValue:是一个返回值 它是一个可选参数,如果传入值的话,callback里面的参数acc的初始值就是这个传入的  值,如果不传入的话acc初始值就是数组中的第一个元素
        callback:回调函数 callback里面的参数
            acc:返回值(每次回调之后的返回值)
            currentValue:当前进行回掉的值
            currentIndex:当前回调的值对应的索引 
    */
   const letterList="abcadefrdc";
   const arr=letterList.split("");//将字符串转换成数组
   const result=arr.reduce(function(acc,cur){
     acc[cur]?acc[cur]++:acc[cur]=1;//第一次:相当于acc.a 没有值,走后 ;等到再次遇到a,acc.a=1 ,有值,走前
     return acc
   },{})
   console.log(result);
}
//此代码目的:字符串中每个元素重复出现的个数

简单解析版

// 解析上方代码
const letterList="abcadefrdc";
   const arr=letterList.split("");
   const result=arr.reduce(function(acc,cur){
     if(acc[cur] !==undefined){
        acc[cur]++
     }else{
        acc[cur]=1
     }
     return acc
   },{})
   console.log(result);

再来解析     /  acc 相当于下面代码中的 a  /  acc[cur]?acc[cur]++:acc[cur]=1

let obj={};//一开始为空
// obj["a"] ? obj["a"]:obj["a"]=1;//相当于判断obj.a里有值么,如果有,就自增,如果没有,就obj["a"]=1
// obj["a"] ? obj["a"]++:obj["a"]=1; //判断obj.a里有值么,有为true,选择自增,因为上面代码obj["a"]=1再自增就为2

③ reduce 展开多层数组 

{
    // 展开多层数组
    const list=[1,['2nd',2,3,['3rd',4,5]],['2nd',6,7]]
    const deepFlat=function(arr){
           reduce(function(acc,cur){
             return acc.concat(Array.isArray(cur)? deepFlat(cur):cur)
           },[])
    }
    let result=deepFlat(list);
    console.log(result);
}

九、对象中扩展运算符的使用

安装es8 插件

babel 不支持 es8的语法,所以要安装插件

①在终端输入

npm i babel-plugin-transform-object-rest-spread

"plugins": ["transform-object-rest-spread"]  添加到 .babelrc 里面

{
    "presets": ["es2015"],
    "plugins": ["transform-object-rest-spread"]
    }

③运行 在终端输入

npm run dev

使用

① 复制对象 ...

注意:简单数据类型时使用扩展运算符是没问题的,但是如果扩展运算符展开对象以后还是一个对象,复制的就是一个指针了

{
    // 对象中扩展运算符的使用
    // 复制对象
    const obj={name:'tom',age:19}
    // 在对象中使用扩展运算符测试之前需要安装npm i babel-plugin-transform-object-rest-spread 插件,然后在.babelrc文件中加入配置 "plugins": ["transform-object-rest-spread"] ,然后重新npm run dev
    let obj2={...obj}
    console.log(obj2);

    // 设置对象默认值
    let obj3={...obj,name:'jerry'}//相当于复制obj 但是把name改为jerry
    console.log(obj3);

    // 合并对象
    let initObj={color:'red',a:{aaa:'aaa'}}
    let obj4={...obj,...initObj}//注意这里有逗号
    console.log(obj4);
    initObj.a.aaa='bbb'
    console.log(obj4);
    // 坑:
    // 简单数据类型时使用扩展运算符是没问题的,但是如果扩展运算符展开对象以后还是一个对象,复制的就是一个指针了
}
{
    
    let name='神经质土豆'
    let age=19;
    let es5Obj={
        name:name,
        age:age,
        say:function(){
           console.log("es5");
        }
    }

 //es6 : key value是一样的,可以只写一个,还可以省略function
    let es6Obj={
        name,
        age,
        say(){
            console.log("es6");
        }
    }
}

 ②  Object.is() 和 === 

  • NaN跟任何数包括自己 === 都是 false
  • Object.is 就是true
{
    //  Object.is() 和 ===
    let result=Object.is(NaN,NaN)
    console.log(result,NaN===NaN);

}

 ③Object.assign() 复制对象

  • Object.assign() 复制对象  一层对象很好用,如果两层对象的话,复制的就是指针了。修改的话,原对象也会被修改。
{
    // Object.assign() 复制对象 
    const person={name:'xm',age:19,cars:{carname:"法拉利"}};
    let person2={};
    // 参数1: 目标对象 参数2:来源对象
    Object.assign(person2,person)
    console.log(person2);
    
    person.cars.carname='兰博基尼'
    console.log(person2);

}

⑤ Object.keys() ,Object.values()  , Object.entries()

  •    Object.keys()  遍历所有属性的名字
  •    Object.values()  遍历所有属性的值
  •    Object.entries()  遍历所有键值对
{
    // Object.keys()  遍历所有属性的名字
    // Object.values()  遍历所有属性的值
    // Object.entries()  遍历所有键值对
    const json={name:'tom',age:19,gender:'男'};
    console.log(Object.keys(json));
    console.log(Object.values(json));
    console.log(Object.entries(json));

    // 将json中的数据复制到obj中
    let obj={};
    for(const k of Object.keys(json)){
         obj[key]=json[key];//相当于 obj.name=json.name
    }
    console.log(obj);
}

十、Map与WeakMap结构的特点

map 数据类型

①创建和添加  let map=new Map()  、set()    参数1:key  参数2:value  

 let map=new Map();
 map.set([1,2,3],"aaa");
    console.log(map);
  •  每一个数组都是map中的一个值,数组中的第一个值为k,第二个值为value
  •  let map=new Map([["第一个数组的k","第一个数组的value"],["第二个数组的k","第二个数组的value"]])
  • 获取长度 size
let map2=new Map([["name","tom"],["gender","male"]])
    console.log(map2);
    console.log(map2.size);//获取长度 size
  • 赋值的时候如果对同key名进行赋值,下面的会覆盖上面的,而且赋值操作也可以链式编程

 let map2=new Map([["name","tom"],["gender","male"]])
 map2.set("name","jerry").set("hobbies",["reading","singing"])
    console.log("map",map2);

获取值 get()    

        如果获取对应的key不存在,会返回undefined

console.log("get",map2.get("hobbies"));

③ 判断 has()

         判断当前map中是否包含某个k

console.log("has",map2.has("age"));//没有age这个属性,故返回false

④删除操作 delete()

map2.delete("hobbies");
    console.log("delete",map2);

⑤清空操作 clear()

 map2.clear();
    console.log("clear",map2);

⑥ map 中也有 keys()  values()  entries()

 const map =new Map([
        ['name','小明'],
        ['age','20']
    ]);
    for(let key of map.entries()){
             console.log(key);
    }

WeakMap

元素只能是对象 ,无法遍历,没有size 和clear 属性

 let weakmap=new WeakMap([
        // ["name","jack"] //不对
        [{aaa:"aaa"},"jack"]
    ])
    console.log(weakmap);

遍历方法 for each

for each方法主要是针对数组而言的,对数组中的每个元素可以执行一次方法

var array = ['a', 'b', 'c', 'd'];
array.forEach((a)=> {
  console.log(a);
});

for each方法主要有三个参数,分别是数组内容、数组索引、整个数组

十一、Set与WeakSet结构的特点

Set

set是es6给开发者提供的一种类似数组的数据结构,可以理解为值的集合,他和数组最大的区别在于:它的值不会有重复项 

内部使用的是Object.is() ,判断值是否相同,不判断数据类型

①创建 

 let set=new Set([1,2,3,4,5,1])
    console.log(set);

②添加元素 add()

let set=new Set([1,2,3,4,5,1])
    console.log(set);
    // 添加元素
    set.add(1);
    console.log(set);

 获取长度  size

console.log("size",set.size);//获取长度   

③判断属性存不存在has()  注意下方代码!这里有坑!!

 let set=new Set();
    set.add({fruit:"apple"})
    // console.log("has",set.has({fruit:"apple"}));//返回false 因为这两个对象是不同的
    const item={fruit:"apple"};
    set.add(item);
    console.log(set.has(item));//这里返回的是true

④删除属性 delete()

⑤清空属性 clear()

⑥keys()  values()  entries()   在set中,key和value是相同的

 const set=new Set([1,2,3,4,5])
    for(let k of set.keys()){
        console.log(k);
    }
    for(let value of set.values()){
        console.log(value);
    }

最大的使用场景:数组去重

注意:利用Array.from 将数据类型转换为数组

 const arr=[1,1,1,2,3,4,2,4,4,5,7,8,9]
    let set=new Set(arr);
    let arr2=Array.from(set);//这步 是将set里的数据类型转化为数组 利用Array.from
    console.log(arr2);

 WeakSet  

元素只能是对象 无法遍历,没有size 和clear

十二、数组、对象、map、set 增删改查

{
    // 数组、对象、map、set 增删改查
    let arr=[];
    let obj={};
    let map =new Map();
    let set=new Set();
 
    const item={fruit:"apple"}
    // 添加
    arr.push(item);
    obj['fruit']='apple';
    map.set('fruit','apple')
    set.add(item);
    console.log("add",arr,obj,map,set);

    // 查询
    const resultArr=arr.includes(item);
    const resultObj='fruit'in obj;
    const resultMap=map.has('fruit');
    const resultSet=set.has(item);
    console.log("has",resultArr,resultObj, resultMap,resultSet);

    // 修改
    arr.forEach(function(item){
        item.fruit=item.fruit? "orange":"" //后面的item.fruit 是判断这个属性存不存在,若存在则赋值为orange,否则为空
    })
    obj['fruit']='orange';
    map.set("fruit","orange");
    set.forEach(function(item){
        item.fruit=item.fruit? "orange":""
    })
    console.log("undata",arr,obj,map,set);

    // 删除
    const index=arr.findIndex(function(item){
        return item.fruit //如果这个属性存在 ,则返回对应的索引
    })
    console.log(index);

    arr.splice(index,1);  //参数1:从哪个元素开始删   参数2:删几个
    delete obj.fruit;
    map.delete("fruit");
    set.delete(item);
    console.log("delete",arr,obj,map,set);
}

十三、类型转换

{
    // 类型转换 
    // 一、map和对象转换
    let obj={
        name:'tom',
        age:19
    }
    // (1)对象转map
    // 由于map中要接受的是键值对数组,所以想要转换成map之前,需要将对象转换为键值对数组,通过Object.entries()这个API进行转换
    console.log(Object.entries(obj));
    let map=new Map(Object.entries(obj));
    console.log(map);
    // (2)map转对象
    // 通过Object.fromEntries这个API进行逆转换
    let obj2=Object.fromEntries(map);
    console.log(obj2);

    // 二、数组和set转换
    // (1)数组转set
    let arr=[1,2,3,4];
    let set =new Set(arr);
    console.log(set);
    // (2)set转数组
    let arr2=Array.from(set);
    console.log(arr2);



}

十四、ES6中的代理Proxy和反射Reflect

Proxy

概叙:proxy是es6为了操作对象引入的API,它不直接作用在对象上,而是作为一种媒介,如果需要操作对象的话,需要经过这个媒介的同意

{
    let obj = {
        id: 1234,
        name: 'admin',
        phone: "123456789",
        create_time: "2022",
        _private: 'test'
    }

    let objProxy = new Proxy(obj, {
        // 拦截、读取和设置操作
        // 需求:对手机号码中间四位换成****,创建时间换成2023
        get: function (target, key) { //target代表当前的对象
            switch (key) {
                case 'phone':
                    return target[key].substring(0, 3) + "****" + target[key].substring(7)
                    break;
                case 'create_time':
                    return target[key].replace("2022", "2023")
                    break;
                default:
                    return target[key]
                    break;
            }
        },
        // 设置: 需求:如果要设置的是id就不允许,如果是id就赋值为之前的那个默认值,其他属性可以正常赋值
        set: function (target, key, value) {
            if (key === "id") {
                return target[key]
            } else {
                return target[key] = value
            }
        },
        // 拦截 key in obj 就是判读某个key是否在对象中存在的操作
        has: function (target, key) {
            if (key in target) {
                console.log(`${key}:`, target[key]);
                return true
            } else {
                console.log("查无此属性");
                return false;
            }
        },
        // 拦截 delete 需求:假如要删除的属性以下划线开头(私有属性),不允许删除,其他属性可以进行删除
        deleteProperty: function (target, key) {
            if (key.indexOf("_") === 0) {  //indexof() 判断字符串中是否有这个字符并返回对应的索引 
                console.warn("私有属性不能被删除")
                return false;
            } else {
                delete target[key];
                return true;
            }
        },
        // 拦截 Object.keys() 遍历所有的属性名。   需求:如果是id或者私有属性就过滤掉
        //filter() 方法用于把Array中的某些元素过滤掉,然后返回剩下的未被过滤掉的元素
        //  1、filter() 不会对空数组进行检测; 2、filter() 不会改变原始数组。

        ownKeys(target) {
            return Object.keys(target).filter(function (item) {
                return item !=='id'  && item.indexOf("_") !== 0
            })
        }
    })
    console.log("拦截读取", objProxy.phone, objProxy.create_time, objProxy.name);

    objProxy.id = 4567;
    objProxy.name = 'tom';
    console.log("拦截设置", objProxy.id, objProxy.name);

    console.log("拦截 in", "sex" in objProxy);//判断这个属性有没有
    console.log("拦截 in", "name" in objProxy);

    console.log('拦截删除',delete objProxy["_private"]);
    // console.log('拦截删除', delete objProxy["name"]);

    console.log("拦截 Object.keys()", Object.keys(objProxy));
}

Reflect

就是操作对象的属性和方法的另外一种方式,推荐使用Reflect,这样操作更加直观

 let obj = {
        name: 'jerry',
        age: 20,
        sex: 'male',
        hobbies: 'running'
    }
    console.log(Reflect.get(obj, 'name'));//获取

    Reflect.set(obj, "name", "tom");//设置
    console.log(obj.name);
    
    'name' in obj;
    console.log(Reflect.has(obj,'name') );//看属性存不存在

一个小案例

现在html布局 再引入js

 <h1>您输入的是:<span id="txt"></span></h1>
    <input type="text">
{
    // 获取dom元素
    const inp=document.getElementsByTagName("input")[0];
    const txt=document.getElementById("txt");
    // 初始化代理对象
    const obj={}
    // 代理选项
    const handler={
        get:function(target,key){
            return Reflect.get(target,key)
        },
        set:function(target,key,value){
           if(key==='text'){
           inp.value=inp.value  === value? inp.value:value;
           txt.innerHTML=value;
           }
           return Reflect.set(target,key,value)
        }
    }
    let objProxy=new Proxy(obj,handler);
    // 给input绑定键盘弹起事件
    inp.addEventListener("keyup",function(event){
           objProxy.text=event.target.value
    })
}
// 1.获取dom对象
// 2.设置代理对象
// 3.配置代理选项
// 4.添加事件
// 5.实现双向数据绑定

十五、rest

rest 函数中形参以外剩余的参数,如果函数中没有其他的形参,rest代表所有传过来的参数(以数组形式存储)

{
    // 默认参数
    function es5Fn(x,y){
        y= y || 'word';
        console.log('es5',x+y);
    }
    es5Fn("hello",'')

    function es6Fn(x,y="world"){ //es6才有
       console.log("es6",x+y);
    }
    // es6Fn('hello')
    es6Fn('hello','haha')
}
{
    // rest 函数中形参以外剩余的参数,如果函数中没有其他的形参,rest代表所有传过来的参数(以数组形式存储)
    function add(x,...rest){
          console.log(rest);//接受传过来剩余的参数 数组形式
          let sum=0;
          for(let value of rest){
            sum+=value;
          }
    }
    add(1,2,3,4,5)
}
{
    // 数组展开 这样会将后面的数组展开 一个一个输出
    console.log(...[1,2,3,4,5]);
}

在函数调用后返回另一个函数的调用,这种称之为尾调用,如果后面有任何其他任何运算,都不是尾调用

{
    // 尾调用
    function fn2(){
        console.log('尾调用');
    }
    function fn1(){
        // 在函数调用后返回另一个函数的调用,这种称之为尾调用,如果后面有任何其他任何运算,都不是尾调用
        return fn2()
        // return fn2()+1 //这就不是尾调用了 因为有运算
    }
}

十六、箭头函数

简写 :如果参数列表只有一个,可以省略小括号;如果函数体中只有一句代码,可以省略大括号;如果这句代码,作为函数的返回值,可以省略retnrn关键字

特点:更短的函数、不绑定this、箭头函数没有argument

{
    // 声明函数
    const arrow = (x) => {
        // console.log("箭头函数",x);
        return x * 2
    }
    arrow(123);
}
{
    //  简写 :如果参数列表只有一个,可以省略小括号;如果函数体中只有一句代码,可以省略大括号;如果这句代码,作为函数的返回值,可以省略retnrn关键字
    const arrow = x => x * 2
    arrow(4)
    console.log(arrow(3));
}
{
    const obj = {
        name: 'apple',
        age: 8,
        sum() {
            window.setTimeout(()=> {
                console.log(this);
                console.log(this.age);
            }, 1000)
        }
    }
    obj.sum()
}

js中什么时候使用箭头函数?

Object.method()   (也就是想要执行这个函数的话,需要某个对象点方法名的方式的话)调用的话就用普通函数,其他情况下都用箭头函数

十七、类的概念&类的封装及继承

  • es5的时候是通过构造函数来实现类的功能的
{
    // es5的时候是通过构造函数来实现类的功能的
    function Person(name,age){
         this.name=name
         this.age=age
    }
    Person.prototype.say=function(){
        console.log(`大家好,我叫${this.name},我今年${this.ageage}岁了`);
    }
    const p=new Person("小明",18);
    console.log(p);
    p.say();
}
  •  es6 改造es5实现类的方式
{
    // es6 改造es5实现类的方式
    class Person{
        constructor(name,age){
            this.name=name
            this.age=age
        }
        say(){
            console.log(`大家好,我叫${this.name},我今年${this.ageage}岁了`);
        }
    }
    const p=new Person("小明",18);
    console.log('class',p);
    console.log(typeof Person);
    p.say();
}
  • 类的继承
{
    // 类的继承
    class Person{
        constructor(name='p'){
             this.name=name;
        }
    }
    class Child extends Person{
        constructor(name='c',age=10){
             //super关键字 要放在构造函数的最前面 作用:调用父类的构造方法
            super(name)
            this.age=age
        }
    }
    console.log("继承",new Child());
}
{
    class Person{
        constructor(name='东方'){
            this.name=name;
       }
    //类 中的get和set看上去是一个函数,但是其实它不是函数而是一个属性    
        get fullName(){
            // "\xa0" 空格的转义符
            return this.name+"\xa0"+"青苍"
        }
        set fullName(value){
            this.name=value
        }
    }
    const p=new Person();
    console.log("get",p.fullName);
    p.fullName="小兰花"
    console.log("get",p.fullName);
}

十八、静态方法

只在当前类中可用,其他子类中不能用,不能用于实例对象

通过static关键字修饰的方法就是静态方法

{
    // 静态方法
    //只在当前类中可用,其他子类中不能用,不能用于实例对象
    class Person{
        // 静态属性,这种写法在java中是可以的,但是在js中会报错
        // static age=10 会报错
        constructor(name='p'){
             this.name=name;
        }
        // 通过static关键字修饰的方法就是静态方法
        static sayHello(){
            console.log("static方法");
        }
    }
    const p=new Person();
    // p.sayHello() 无法调用
    Person.sayHello() //可调用

    // 静态属性
    Person.age=10;
    console.log(Person.age);
}

十九、import和export

// 按需导入 需要:html文件中需要更改为<script src="./src/demo5-4-1.js" type="module"></script>
// 并且运行html是需要以服务的方式运行,不要以文件方式运行
// import {a,say} from  "./demo5-4-2.js" //以服务方式可以运行 
// console.log(a);
// say()

// 全部导入
import * as aaa from "./demo5-4-2.js" //将获取来的都存到aaa这个对象里
console.log(aaa);

// 
import bbb from "./demo5-4-2.js"
console.log(bbb);

// 下面这种方式相当于在默认的export对象中加入某个属性
// export let a=3;

// export function say(){
//     console.log('hello');
// }

// export class test{
//     sayHello(){
//         console.log('sayhello');
//     }
// }

export default{
   b:5,
   say(){
    console.log("default say");
   }
}

二十、什么是异步编程及js的异步实现

{
    // 异步
    console.log(1);
    setTimeout(()=>{
        console.log(2);
    },0)
    console.log(3);
}
//输出 1  3  2

二十一、 Promise

回调地狱

// 回调地狱
    // 一层回调
    function ajax(cb){
        setTimeout(()=>{
            cb && cb();//判断往没往里传参数,传了为true,回调,不传为false,cb()会报错
        },1000);
    }
    ajax(()=>{
        console.log('任务1');
    })



 // 两层回调
    // 需求:在执行完任务1之后执行任务2,定义一个回调函数的时候要定义一个参数来接收第二个回调函数
    function ajax(cb){
          setTimeout(()=>{
            cb&&cb(()=>{
                console.log('任务2');
            })
          },1000)
    }
    ajax((cb2)=>{
        console.log('任务1');
        setTimeout(()=>{
            cb2&&cb2();
        })
    })

Promise改造回调函数

   function ajax(){
         return new Promise((resolve,reject)=>{
            setTimeout(()=>{
                    resolve()
            },1000)
         });
    }  
    console.log(ajax());
    ajax().then(()=>{
        console.log('任务1');
    })
 // 针对两次回调为例,用promise方法
    function ajax() {
        return new Promise((resolve, reject) => {//resolve 代表正确 reject代表错误
            setTimeout(() => {
                resolve()
            }, 1000)
        });
    }
    ajax().then(()=>{
        console.log('任务1');
        return new Promise((resolve, reject) => {
            setTimeout(()=>{
                resolve()
            },1000)
        }).then(()=>{
            console.log("任务2");
        })
    })

使用catch方法捕获错误

 function fn(num){
        return new Promise(()=>{
            if(typeof num==="number"){
                resolve(num)
            }else{
                const err=new Error("请输入数字")
                reject(err)
            }
        })
    }
    fn(3).then(n=>console.log(n))
         .catch(e=>console.log(e)

Promise.all 方法


    // Promise.all 方法 
    const imgUrl1='https://img2.baidu.com/it/u=1641927010,1941805886&fm=253&fmt=auto&app=138&f=JPEG?w=890&h=500'
    const imgUrl2='https://img2.baidu.com/it/u=763721447,473124631&fm=253&fmt=auto&app=120&f=JPEG?w=690&h=388'
    const imgUrl3='https://img2.baidu.com/it/u=3450065074,1356681687&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=750'
    function getImage(url){
            return new Promise((resolve,reject)=>{
               const img=document.createElement("img")
               img.src=url;
               img.onload=()=>resolve(img)
               img.onerror=()=>reject(err)
            })
    }
    // 渲染所有图片的方法
    function showImage(imgs){
        imgs.forEach(item => {
             document.body.appendChild(item);
        });
    }
    function showFirstImage(ima){
        document.body.appendChild(img)
    }

    // 用来判断参数(数组)中所有的promise是否全部执行完毕,当全部执行完毕之后才会执行.then
    Promise.all([getImage(imgUrl1),getImage(imgUrl2),getImage(imgUrl3)]).then(showImage)

    // 用于希望多个promise函数当中只要有一个执行完毕就会触发.then
    Promise.race([getImage(imgUrl1),getImage(imgUrl2),getImage(imgUrl3)]).then(showFirstImage)

二十二、interator 方法

{
    // interator 方法
    const arr=[1,2,3]
    const fn=arr[Symbol.interator]()
    console.log(fn);
    console.log(fn.next());
    console.log(fn.next());//next 他自己就往下输出了,直至完毕,done变为true
    console.log(fn.next());
    console.log(fn.next());
}
 const obj={
        name:'东方青仓',
        age:20,
        gender:'male',
        [Symbol.interator](){
            let index=0;
            // 通过values获取对象中所有的属性值
            const values=Object.values(this)
            return {
                next (){
                    if(index<values.length){
                         return{
                            value:values[index++],
                            done:false
                         }
                    }else{
                        return{
                            done:true
                        }
                    }
                }
            }
        }
    }
    for(const value of obj){
       console.log(value);
    }

二十三、Generator

  1. 在Generator使用之前需要安装一个依赖 npm i babel-polyfill -s这个依赖可以是babel转义es6里一些新的API

  2. 然后将node_modules里面的polyfill.js复制到外面,再到index.html中引入这个js文件

  const say=function*(){  //加上*号,就是generator函数
       yield 'a'  //相当于return 但是return只能return一次,而yield可以多次
       yield 'b'
       yield 'c'
       yield 'd'
    }
    const fn=say();
    console.log(fn.next());
    console.log(fn.next());
    console.log(fn.next());
    console.log(fn.next());
    console.log(fn.next());
{
    let obj={
        a:1,
        b:2,
        c:3,
    }
    obj[Symbol.iterator]=function*(){
        for(const k of Object.keys(obj)){
           yield obj[key]
        }
    }
    for(let value of obj){
         console.log(value);
    }
}

应用场景

// 应用场景
    // 状态机:任何时候都只有一定数量的状态
    const state=function*(){
        while (true) {   //死循环
            yield 'success'
            yield 'fall'
            yield 'padding' 
        }
    }
    const stateDate=state();
    console.log(stateDate.next());
    console.log(stateDate.next());
    console.log(stateDate.next());
    console.log(stateDate.next());
    console.log(stateDate.next());
    console.log(stateDate.next());
    console.log(stateDate.next());
}

二十四、async(必须搭配await用)

{
    // async
    async function fn(){
        await console.log(1);
        await console.log(2);
        await console.log(3);
    }
    fn();
}

举个小例子:(以下代码为异步实现,log内容会一起输出显示)

{
    function fn1(){
        setTimeout(()=>{
            console.log('任务1');
        },1000)
    }
    function fn2(){
        setTimeout(()=>{
            console.log('任务2');
        },1000)
    }
    function fn3(){
        setTimeout(()=>{
            console.log('任务3');
        },1000)
    }
    function init(){
        fn1();
        fn2();
        fn3()
    }
    init();

让函数一个一个蹦出来 变成了同步的一种形式

{
    // 让函数一个一个蹦出来 变成了同步的一种形式
    function fn1(){
        return new Promise(resolve=>{
            setTimeout(()=>{
                console.log('任务1');
                resolve();
            },1000)
        })
    }
    function fn2(){
        return new Promise(resolve=>{
            setTimeout(()=>{
                console.log('任务2');
                resolve();
            },1000)
        })
    }
    function fn3(){
        return new Promise(resolve=>{
            setTimeout(()=>{
                console.log('任务3');
                resolve();
            },1000)
        })
    }
    async function init(){
        await fn1();
        await fn2();
        await fn3();

    }
{
    function f(){
        return new Promise(resolve=>{
          resolve('东方大强三界最强')
        })
    }
    // function f2(){
    //     fn().then(response=>(){
    //     console.log(response);
    //     })
    // }
    async function f2(){
        const x= await f()
        console.log(x);
    }
    f2();
    
}

     


猜你喜欢

转载自blog.csdn.net/m0_65085680/article/details/127337230
今日推荐