Es6-Es11
1.let
1.不能重复声明
2.块级别作用域 全局 函数 eval
3.不存在变量提升
4.不影响作用域链
5.用途举例:a.点击5个div
2.const
1.大写
2.必须赋值
3.不能修改
4.块级作用域
5.对于引用类型的修改 不算修改
3.let {} = zhao //结构化赋值
4.let b="hello",str = `abcd5${b}`;//模板字符串
5.对象简化
1 let name = "zhagnsan",say = funtion(){console.log("I am zhangsan")}; 2 let person = {name,say,play(){console.log("I can play")}}
6.箭头函数
a.()=>{}
b.this 静态只和定义时候的环境有关
1.哪怕fn.call调用也不行
c.不能作为构造函数来使用
d.没有arguments 如果使用会提示 undefiend
e.简写
0.省略小括号,有且只有一个参数
1.省略花括号,n=>n*n(有切仅有一个参数,仅有一句返回且不能有 return)
f.应用场景:
1.点击div 2秒后变色,普通函数 setTimeout 里面的函数 指向 window 如果是箭头函数 指向div 自己
2.arr.filter(item=>item % 2 == 0);返回数组里面的偶数
7.参数默认值
1.function sum(a,b,c=3){return a+b+c} sum(1,2)
2.与结构赋值相结合
function person({name,age:25}){console.log(name)} let p1={name:"zs"}
person(p1);
3. ...rest 代替 arguments 结果是数组 必须放最后 function(a,b,...args)
4.扩展运算符 和 rest 相反的样子
a.arr = ["a","b"] , function a({console.log(arguments)}) a(arr) 此时 arguments 一个参数 a(...arr) 此时 arguments 两个参数
b.应用如下:
1.a1 = ["a","b"] , a2 = ["c","d"],a2 = [...a1,...a2] 类似 a3 = a1.concat(a2)
2.数组的克隆 避免地址传递
3.伪数组转为真正的数组
8.symbol
1.唯一 let s2 = Symbol("dog"),s3 = Symbol("dog") //在这里 s2 != s3
2.let s2 = Symbol.for("dog"),s3 = Symbol.for("dog")// 在这里 s2 === s3
3.let method={up:Symbol(),down:Symbol()},let bolloon = {up,down} bollon[method.up]=function(){} 不覆盖
4.let person = {[Symbol("say")]:function(){console.log("I can say")}} //Symbol("say")必须有[]
5.class Person{static [Symbol.hasInstance](para){console.log("I am checked")}} console.log({} instanceof Person) 检测对象时候触发 para是对象{}
6.arr2[Symbol.isConcatSpreadable] = fasle;//arr1.concat(arr2) arr2 不展开 //[1,2,3,arr2]
//关于获取Symbol 的文本 Symbol.prototype.description let s0 = Symbol("up"); console.log(s0.description) let s1 = Symbol.for("down"); console.log(s1.description)
9.生成器函数
1.function *gen(){
let res1 = yield fn1();
let res2 = yield fn2(res1);
}
2.iterator = gen();
3.iterator.next() 执行
4.iterator.next("a") 如果第二次执行传参 是第一个 yield 的返回值 也就是说 res1的值是"a"
5.fn2(res1) fn2函数的传参不受影响 正常的参数 和 next 传的参数是yield的返回结果
6.详细理解
1.第一次next执行到 yield fn1() 包含这句话 同时把 fn1() 的结果返回出去 作为 {value:"",state:false} 中 value 的结果 ,但是 fn1() 这个返回结果 并不会给 let res1 = 它只能等外部
1.下一次 外部 next(para) 传参调用后 才会赋值 我给你个value 你给我个参数作为 yield 的 赋值的返回结果 有来有回 来而不往非礼也
2.常见应用
1.生成文章的id function* gen(){let id =0; while(true){yield id;id++}} let id = gen() let artical = {artid:id.next().value,title:"zs"} {artid:id.next().value,title:"zs"}
1.生成器函数写死循环也没有关系
10.promise
let ai = new Promise ((reslove,reject) => { fs.readFile("./wx.txt",function(error,data) { if (error) reject(error); else reslove(data.toString()); }) }) ai.then((data)=>{ console.log(data) },(error)=>{ console.log(error) })
//Promise 中的 allSetted race all 的不同用法 let p1 = new Promise((resove,reject)=>{ setTimeout(()=>{ resove("用户zs登录成功") // reject("用户zs登录失败") },100) }) let p2 = new Promise((resove,reject)=>{ setTimeout(()=>{ resove("用户ls登录成功") // reject("用户ls登录失败") },1000) }); //必须p1和p2都resolve是成功 这个res才是成功的 走 then 的第一个回调 v 是一个数组 里面是所有的 p 的结果 //有任何一个失败 都会走 then 的第二个回调 //如果在一直在等待 promise 的执行结果 状态就是 pending //只要 [p1,p2] 中 发现有一个失败的 类似 && res直接结果就是 result 就是失败的那个结果 状态也是 reject 反之,如果都成功 状态是 fulfilled result 是个数组 let res = Promise.all([p1,p2]); res.then((v)=>{ console.log(res) console.log("ssssss") console.log(v) console.log("-------------------------------") },(v)=>{ console.log(res) console.log("ffffff") console.log(v) console.log("-------------------------------") })
//相同的代码省略掉了 这里 p1 快速 失败 p2 慢些成功 //不管成功失败 只要有一个执行出结果 就是 res最后的值 也就是说 res 只有一个结果 let res = Promise.race([p1,p2]);
//只要全部执行完毕 不管成功失败 对于res状态来说 都是成功的 fullfilled 结果呢永远是所有p的数组 并且是一个promise数组 //race 和 all 返回的是 普通的值 不是 promsie let res = Promise.allSettled([p1,p2])
10.Set
//基本方法属性 let s1 = new Set(["a","b","c"]) console.log(s1.size) // 3 s1.add("d") s1.delete("a") s1.has("b") s1.clear(); //应用 //数组去重复 let a1 = [1,1,3,3,0] let s2 = new Set(a1) a1 = [...s2] console.log(a1) // [ 1, 3, 0 ] //求数组交集 let j1 = [1,2,3,2,3,4,5,3,6]; let j2 = [2,3,2,3] let jres = [...new Set(j1)].filter(item => new Set(j2).has(item)); console.log(jres) // [ 2, 3 ] //求并集 let b1 = [1,3,2,3,2]; let b2 = [2,3,4,5]; let bres = [...new Set([...b1,...b2])] console.log(bres) //[ 1, 3, 2, 4, 5 ] //求差集 let c1 = [1,2,3,2,3,3,1]; let c2 = [3,4,5,6] let cres = [...new Set(c1)].filter(item => !(new Set(c2).has(item))); console.log(cres) // [ 1, 2 ]
11.Map
//基本方法属性 let m1 = new Map() console.log(m1.size) m1.set("name","zs"); m1.set("age","30"); m1.get("name"); console.log(m1) //{ 'name' => 'zs', 'age' => '30' } for (let v of m1){ console.log(v); //[ 'name', 'zs' ] // [ 'age', '30' ] } m1.clear()
12.Es5和Es6类Class
function Phone(brand, price) { this.brand = brand; this.price = price; } //静态属性和方法 Phone.country = "china" Phone.love = function () { console.log("I love china"); } Phone.prototype.call = function () { console.log("I can call phone") } let hw = new Phone("huawei", 999) hw.call() //I can call phone console.log(hw) //Phone { brand: 'huawei', price: 999 } console.log(Phone.country); // china Phone.love() //I love china //Es5对象的继承 function SmartPhone(brand, price, age) { Phone.call(this, brand, price); this.age = age; } SmartPhone.prototype = new Phone(); SmartPhone.prototype.constructor = SmartPhone; SmartPhone.prototype.play = function () { console.log("I can play game"); } let sp = new SmartPhone("chuizi",99.99,1983); console.log(sp) //About Es6
//关于类的私有属性 //Es5 中用闭包的模式来实现私有属性 function Person(name,age){ var age; this.name = name; this.sayName = function(){ console.log("my name is "+ this.name) } this.setAge = function(a){ age = a; } this.getAge = function(){ //这里不能用 this.age console.log("my age is " + age); } } let zs = new Person("zs",99); //只能通过提供的内部方法访问 zs.getAge(); //99 zs.setAge(18); zs.getAge(); //18 //此时zs.age 是 undefined console.log(zs.name,zs.age) console.log("---------------------------") //Es6中私有属性的实现 通过#来实现 class Person1{ #age; name; constructor(name,age){ this.name = name; this.#age = age; } getAge(){ console.log("my age is " + this.#age); } setAge(age){ this.#age = age; } } let p0 = new Person1("ls",88); // 如果访问 p0.#age 会出现错误提示:Uncaught SyntaxError: Private field '#age' must be declared in an enclosing class // 但 p0["#age"] 没问题 提示 undefined console.log(p0,p0.name,p0["#age"]);//{} ls undefined p0.getAge();//88 p0.setAge(77); p0.getAge()//77
13.数值方法的扩展 Number 和 Math
console.log(Number.EPSILON) // 2.220446049250313e-16 console.log(0.1 === 0.3 - 0.2) //false console.log(equal(0.1 , 0.3 - 0.2)) //true function equal(a,b){ if(a - b <= Number.EPSILON){ return true }else{ return false; } } console.log(Number.isFinite(100/0)) //false; console.log(Number.isFinite(Infinity)) //false console.log(Number.isFinite(100.10)) //true console.log(Number.isNaN(Infinity)) //false console.log(Number.isNaN(100/0)) //false console.log(Number.parseInt("5265.36love")) //5265 console.log(Number.parseFloat("5265.36love")) //5265.36 console.log(Number.isInteger(5265.36)) //false console.log(Number.isInteger("5265")) //false console.log(Math.trunc(3.5)) //3 console.log(Math.sign(0)) //返回符号 正数 1 零 0 负数 -1
//about BigInt 之所以引入这个概念是因为 超过最大安全整数的数字 就不安全了 console.log(Number.MAX_SAFE_INTEGER) //9007199254740991 let n0 = Number.MAX_SAFE_INTEGER; //大于这个最大安全整数后再加会出问题 console.log(n0 + 1) //9007199254740992 console.log(n0 + 2) //9007199254740992 //也可以用 isSafeInteger 函数来验证 console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER)) //true console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER + 1)) //false console.log("-----------------------") //数字后面加n就是大整数 但是浮点数后面加n不行 let n1 = 123n; console.log(n1,typeof n1); //123n 'bigint' //把n0 转化为 bigInt 就不会出错了 let n2 = BigInt(n0); console.log(n2,typeof n2) //9007199254740991n 'bigint' console.log(n2 + BigInt(1)) //9007199254740992n console.log(n2 + BigInt(2)) //9007199254740993n //BigInt 类型和普通的类型无法直接相加 需要把普通的整数转化为 BigInt 类型才能相加 console.log(n2 + 1) //报错: test.js:51 Uncaught TypeError: Cannot mix BigInt and other types, use explicit conversions
14.进制相关
//各种进制 let n2 = 0b1010; let n8 = 0o771; let n10 = 998; let n16 = 0xff;
15.Object 对象的方法补充
//对象方法的扩展 console.log(NaN === NaN) //false console.log(Object.is(NaN, NaN)) //true //全等 相当于 === 可判断 NaN 是否等于 NaN //对象的合并 let con1 = { host: "192.168.0.11", port: 80, password: "admin" } let con2 = { password: "nopwd", charset: "utf-8" } console.log(Object.assign(con1, con2)) //{ host: '192.168.0.11', port: 80, password: 'nopwd', charset: 'utf-8' }
相当于 {...con1, ...con2} 都展开 后面会覆盖前面
console.log(con1) //{ host: '192.168.0.11', port: 80, password: 'nopwd', charset: 'utf-8' } //设置对象的原型对象 let o1 = { name: "songjiang" } let o2 = { nativePlace: "liangshan" } Object.setPrototypeOf(o1, o2); //o1的 prototype 是 o2 o2的 prototype 是 Object
//对象方法的扩展 let oStu = { name:"zs", hoobies:["smoking","drinking","perm"], friends:["zs","ls","ww"] }; console.log(Object.keys(oStu)); console.log(Object.values(oStu)); //获取对象的 entry 是一个 数组 套数组 [0:[k,v]] let mapElements = Object.entries(oStu); console.log(mapElements) //entries 正好可以用户 new Map的参数 [0:[k,v],1:[k1,v1]] let map1 = new Map(mapElements); console.log(map1); //获得对象的每个属性的定义描述符号 console.log(Object.getOwnPropertyDescriptors(oStu)); //定义一个prototype 为 null的对象 和 {} 效果不一样 cObj.__proto__ 会是 Object,但 Object.setPrototypeOf(cObj,null) 的 cObj.__proto__ 会是 undefined //和 Object.setPrototypeOf(cObj,{}) 功能类似 let cObj = Object.create({},{ name:{ value:"zs", writable:true, enumerable:false, cofigurable:true }, age:{ value:26, writable:false, enumerable:true, configurable:false } }) //cObj 的 age 属性是不可以删除的 因为 age的 configurable 为 false,并且不可以更改,因为writable 为false //cObj 的 name 属性 不可以通过 for in 枚举出来 因为 enumerable 为 false cObj.name = "武松"; cObj.age = 99; console.log(cObj) for (let k in cObj){ console.log(k +"-->" + cObj[k]) }
//对象的 Object.fromEntries //Object.entries 把对象转成一个二维数组 而 fromEntries 正好相反 把二维数组转成对象 let stu = { name:"zs", age:18 } let res = Object.entries(stu); console.log(res) //把二维数组转成对象 let stu2 = Object.fromEntries(res); console.log(stu2) //Map 可以 直接把二维数组转换成Map let map1 = new Map(res); console.log(map1) //fromEntries 可以直接把 Map 转为对象 map1.set("school","红旗小学"); let stu3 = Object.fromEntries(map1); console.log(stu3);
//可选链操作符 如果有就显示 如果没有 就是 undefined 类似 option && option.user && option.user.name function config(option){ let user = option?.user?.name; let pwd = option?.user?.pwd; let cache = option?.user?.cache; console.log(user,pwd,cache); } let option = { host:"192.168.0.1", port:8080, user:{ name:"zs", pwd:"1111" } } config(option);//zs 1111 undefined
//??怎么用呢
let a = obj.name || "zs" 只有当 obj.name 为 null 或 undefined a="zs" 和 || 语法是有区别的
16.模块化开发
//模块化 //Es6之前由社区开发的模块有 //1.CommonJS => NodeJS Browserify //2.AMD => requireJS //3.CMD => SeaJS //Es6 模块化语法主要有 export 和 import 两个命令来完成 //export //1.分别暴露 t1.js export let school = "红星小学"; export function study(){ console.log("我们要好好学习") }
//demo.js var num = 123; export var age = 18; export var name = 'tom'; export default num; //index.js import AA, {age,name} from './demo.js'; console.log(AA,age,name); // AA就是demo.js中默认导出的num AA 可以写在前面 但是不可以写在后面 比 i
mport {age,name},AA
from './demo.js'; 报错
// default 仅仅是一个特殊的导出变量而已 {default:default}
//在一个模块中export default 只能使用一次,export可以多次
var num = 123; export default num; //错误写法 export default var num = 123; //因为export default num 的意思是把变量num的值赋值给变量default; //所以不能写成export default var num = 123;
引用时候import num from 'demo.js';
//或者
import aa from 'demo.js';
//注意不能加 {}
//在页面引用模块
//模块的动态 import 比如 当点击的时候导入模块 不点击的话就不导入 function dynamicImport(){ const btn = document.querySelector("#btn"); btn.onclick = function(){ import("./es6Mod.js").then((module)=>{ console.log(module); }) } } dynamicImport();
17.array 数组的 一些特性
array0 = ["a", "b"] console.log(array0.includes("a"))// true console.log(array0.indexOf("a"))// 0
//Array.flat Array.flatMap let arr1 = [1,2,3,[4,5,[6,7,8]]] //[6,7,8]不做扁平化处理 console.log(arr1.flat(1)) //扁平化处理深度为2 变成 一维数组 console.log(arr1.flat(2)) arr1 = [1,2,3] let arr2 = arr1.map(function(v,k,ori){ return [v*2,k]; }) //返回数组后 新的数组就是一个二维数组 console.log(arr2) arr2 = arr1.flatMap(function(v,k,ori){ return [v*2,k]; },1) console.log(arr2)
18.async 函数 await
async function ac() { //返回非promise的任何数据 都会返回一个 状态为 fulfilled 的promise 对象,默认返回一个 undefined 状态为 fullfilled 的 promise 对象 //如果返回 promise 函数的结果就是 这个promise 对象 //如果抛出错误 或者发生错误 结果为 状态为 rejected 值 为抛出的错误 或者发生的错误 fewfwefwff } console.log(ac())
async function ac() { //await 必须写在 async 函数里面 //await 右侧的表达式一般为 promise 对象 //await 返回的是 promise 的 成功的值 //await 后面的 promise 如果失败了 就会抛出异常 需要有 try catch 来捕获
//await 后面当然 也可以跟返回结果 非 promise 表达式,比如 3 那么 let res = await e // res 的结果就是3 不会报错 let res; try { //resolve("success la") 走这里 // res 为 resolve() 里面的 结果的类型 res = await new Promise(function(resolve,reject){ // resolve("success la") reject("failure la") }) } catch (error) { //reject("failure la") 走这里 // res 是 string 类型 res = error; } console.log(typeof res); return res; } console.log(ac())
//应用 let fs = require("fs") function readFile(path){ return new Promise(function(resolve,reject){ fs.readFile(path,function(error,data){ if(error) reject(error); else resolve(data.toString()) }) }) } async function readMn(){ let res; try { let pre = await readFile("./minnongPre1.txt"); let suf = await readFile("./minnongSuf.txt"); res = pre + suf; } catch (error) { res = error; } return res; } readMn().then((data)=>{console.log(data)});
19.关于正则的regexp的一些用法
//正则命名分组 普通的正则分组 exec执行后 res[0] 是匹配到的全部 res[1] 开始是分组匹配到的内容 index:2 表示从2开始匹配到 //groups 如果没有命名分组 那么是 undefined 如果是命名分组 let str = "ccname:武松8sjfsjf332age:83fwefi99" + "ccname:林冲8sjfsjf332age:82fwefi99" let reg = /name:(?<name>.*?)8.*?age:(?<age>.*?)fw/sg; let res = reg.exec(str) console.log(res) //显示分组后的内容 以分组时候给的名字作为 groups中的key console.log(res.groups.name)
//正向断言和反向断言 a(?=bbb) (?<=bbb)a 不作为匹配返回结果 不作为子匹配 //正向反断言和反向反断言 a(!bbb) (?<!bbb)a let str = "ccname:武松打狗888sjfsjf332age:83fwefi99" + "ccname:武松打虎999sjfsjf332age:82fwefi99" let str2 = "武松英雄" let reg = /武松(?=英雄)/; // let reg = /name:(?<name>.*?)8.*?age:(?<age>.*?)fw/sg; let res = reg.exec(str) console.log(res) //没有匹配到 null res = reg.exec(str2) console.log(res) //匹配到了 武松 后面的 英雄不是返回结果 console.log("---------------------------"); //?: 则需要理解捕获分组和非捕获分组的概念 这里是不捕获 分组 也就是不把分组存储在 $n 中 reg = /武松(?:英雄)/; res = reg.exec(str2) console.log(res) //res[0] 武松英雄,不存在 res[1] console.log("---------------------------"); //关于不捕获分组的经典例子 数字格式化 1,123,000 //关于下面正则的理解 首先 对于 \b 是单词边界 像 空格 逗号 这些符合认知中的单词分割都属于边界 \B 是非单词边界 //所以像 \b \B 这种有两种匹配 1.单词 2.位置(就是边界,比较空的东西 看不到 用 console 查看就是一个空的字符串) //下面的正则就是寻找一个 非单词边界 并且 (?=) 后面断言 必须是 非捕获匹配的 3 个数字 可以重复多次 (?:\d{3})+ //并且 最后不能是数字 (?!\d) 像 1234242fff 都可以替换后变成 1,234,242fff (?!\d)也可以替换成 \b 单词边界 能处理 12345678这种 无法处理 12345678aaff str = "1234567890968fwefwff"; reg = /\B(?=(?:\d{3})+(?!\d))/; res = reg.exec(str); console.log(res); console.log("---------------------------"); let reg_split =/\B(?=(?:\d{3})+(?!\d))/ // let reg_split = /\B(?=(?:\d{3})+\b)/g; res = str.replace(reg_split,",") // 结果:1,234,567,890,匹配的是后面是3*n个数字的非单词边界(\B) console.log(res) res = res.replace(reg_split,",") // 结果:1,234,567,890,匹配的是后面是3*n个数字的非单词边界(\B) console.log(res)
//dotAll匹配模式 /s 默认正则是 . 匹配除了换行之外的任意字符 有时候为了让他匹配换行需要加入 s参数 呼吁事故dotAll 模式 let str = `name:张三3223 age:63aaaaa name:李四3223 age:29aaaaa ` let reg = /name:(.*?)\d+.*?age:(\d+)[a-z]+/g; let res = reg.exec(str); console.log(res) //开启dotAll模式后 就可以匹配到了 //另外如果不使用matchAll 需要用 循环的模式 当匹配到null 结束 来匹配所有数据 let reg2 = /name:(.*?)\d+.*?age:(\d+)[a-z]+/gs; while(res = reg2.exec(str)){ console.log(res) } //matchAll模式 console.log("------------------------------------------"); res = str.matchAll(reg2); console.log(res); //res结果是一个迭代器 iterator 支持 for of 和 next for(let k of res){ console.log(k) } console.log("------------------------------------------"); //用next的模式获取一次 返回一个对象{done:false,value:xxx} value是数值 没有数据后返回 {done:true,value:undefined} res = str.matchAll(reg2); console.log(res) let r; do { r = res.next() console.log(r); } while (!r.done);
20.关于文本String的一些用法
//trimStart trimEnd trim 去掉空格 也没什么说的
21.关于this的研究
//globalThis 在不同平台是不同的 在chrome是window //在nodeJS平台上是 global