# ES6-ES11语法 **Repository Path**: lyc458216/es6-es11-syntax ## Basic Information - **Project Name**: ES6-ES11语法 - **Description**: No description available - **Primary Language**: JavaScript - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-11-02 - **Last Updated**: 2021-03-07 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # ES6-ES11 语法 ## 使用 nrm 工具管理 npm 源 **安装 nrm:** ```bash npm install -g nrm ``` **NRM 常用命令:** ```bash # 查看可选源 nrm ls # 测试 taobao 源响应时间 nrm test taobao # 切换到 taobao 源 nrm use taobao # 增加 taobao 定制源,地址为 http:192.168.0.0.1:8080 nrm add taobao http:192.168.0.0.1:8080 # 删除 taobao 源 nrm del taobao ``` **使用 nvm 可以用来管理不同版本的 node.** ## ES5 中数组遍历方式 **reduce() 接收一个函数作为累加器:** ```js // 使用 reduce 进行累加求和 let sum = arr.reduce(function (prev, cur, index, arr) { return prev + cur; }, 0); // 求出数组中最大值 let max = arr.reduce(function (prev, cur) { return Math(prev, cur); }); // 数组去重 let res = arr.reduce(function (prev, cur) { prev.indexOf(cur) == -1 && prev.push(cur); return prev; }, []); ``` ## ES6 中新增数组方法 **新增的数组遍历方法 for of:** ```js // 遍历数组的值 for (let item of arr.values()) { console.log(item); } // 遍历数组的索引 for (let item of arr.keys()) { console.log(item); } // 索引和值都要 for (let [index, item] of arr.entries()) { console.log(index, item); } ``` **数组中的元素替换 fill:** ```js let arr = [1, 2, 3, 4, 5]; arr.fill("imooc", 1, 3); console.log(arr); // [1, "imooc", "imooc", 4, 5] ``` **可以使用 includes 查找数组中是否含有 NaN:** ```js let arr = [1, 2, 3, NaN]; console.log(arr.includes(NaN)); // true console.log(arr.indexOf(NaN)); // -1 ``` ## 箭头函数 dia 1、不可当做构造函数 2、不可以使用 arguments 对象,但可以使用 rest 运算符获取参数 ```js let foo = (...args) => { console.log(args); }; foo(1, 2, 3); ``` ## ES6 遍历对象 ```js let obj = { name: "123", age: 18, school: "xxx", }; // 方法1 Object.keys(obj).forEach((key) => { console.log(key, obj[key]); }); // 方法2 Object.getOwnPropertyNames(obj).forEach((key) => { console.log(key, obj[key]); }); // 方法3 Reflect.ownKeys(obj).forEach((key) => { console.log(key, obj[key]); }); ``` ## 深拷贝 ```js // 检查类型 let checkType = (data) => { return Object.property.toString.call(data).slice(8, -1); }; // 深拷贝 let deepClone = (obj = {}) => { if (typeof obj !== "object" || object == null) { // obj 不是对象类型,或者 obj 是对象类型但为 null,直接返回 return obj; } // 初始化返回结果 let result; result = checkType(obj) === "Array" ? [] : {}; for (let key in obj) { if (obj.hasOwnProperty(key)) { result[key] = deepClone(obj[key]); } } return result; }; ``` ## ES5 继承 ```js // 父类 function Animal(name) { this.name = name; } Animal.prototype.showName = function () { console.log(`名字是:` + this.name); }; // 子类 function Dog(name, color) { Animal.call(this, name); // 继承属性 this.color = color; } Dog.prototype = new Animal(); // 继承方法 Dog.prototype.constructor = Dog; // 把原型复原 let d1 = new Dog("wangcai", "white"); console.log(d1); d1.showName(); ``` ## ES6 继承 ```js class People { constructor(name, age) { this.name = name; this.age = age; this._sex = -1; // 给类添加静态方法 } get sex() { // 静态类属性的获取 if (this._sex === 1) { return "male"; } else if (this._sex === 0) { return "female"; } else { return "error"; } } set sex(val) { // 静态类属性的设置 if (val === 0 || val === 1) { this._sex = val; } } showName() { console.log(this.name); } static getCount() { return 5; } } let p1 = new People("lyc", 18); console.log(p1); p1.sex = 1; // 父类类的静态属性的设置 console.log(p1.sex); // 父类的静态属性的获取 console.log(p1.getCount()); // 报错,实例调用父类静态方法会报错 class Coder extends People { constructor(name, age, company) { super(name, age); this.company = company; } showCompany() { console.log(this.company); } } let c1 = new Coder("zhangsan", 18, "xxx"); console.log(c1); c1.showName(); c1.showCompany(); c1.sex = 1; // 实例可以继承和获取父类的 get / set 属性 console.log(c1.sex); console.log(Coder.getCount()); // 子类可以继承父类的静态方法 ``` ## symbol() 1、for……in、for……of 循环无法遍历 symbol 属性 2、Object.getOwnPropertySymbols() 只能能获取到 symbol 属性 3、Reflect.ownKeys() 既能获取到普通属性,又能获取到 symbol 属性 ```js // symbol() let s1 = Symbol("foo"); let s2 = Symbol("foo"); s1 === s2; // false // symbol.for():在全局定义 let s1 = Symbol.for("foo"); let s2 = Symbol.for("foo"); s1 === s2; // true ``` 使用 symbol() 去耦合 ```js const shapeType = { triangle: Symbol(), circle: Symbol(), }; function getArea(shape) { let area = 0; switch (shape) { case shapeType.triangle: area = 1; break; case shapeType.circle: ares = 2; break; } return area; } console.log(getArea(shapeType.triangle)); ``` ## set ```js let s = new Set([1, 2, 3, 2]); s.add("imooc").add("es"); // 增 s.delete(2); // 删 s.clear(); // 清空 console.log(s.has("imooc")); // 查 console.log(s.size); // 大小(长度) // 遍历 s.forEach((item) => console.log(item)); for (let item of s) { console.log(item); } for (let item of s.keys()) { console.log(item); // set 的 key 与 value 相同 } for (let item of s.values()) { console.log(item); // set 的 key 与 value 相同 } for (let item of s.entries()) { console.log(item[0], item[1]); // set 的 key 与 value 相同 } // 使用 set 求交集 let s1 = new Set(arr1); let s2 = new Srt(arr2); let result = new Set(arr1.filter((item) => s2.has(item))); console.log(Array.from(result)); // 使用 set 求差集 let arr3 = new Set(arr1.filter((item) => !s2.has(item))); let arr4 = new Set(arr2.filter((item) => !s1.has(item))); console.log([...arr3, ...arr4]); ``` ## WeakSet 1、WeakSet 里只能传入对象,可传入多个对象 2、WeakSet 不能被遍历 ## MAp ```js let map = new Map([ ["name", "xxx"], ["age", 5], ]); console.log(map); // { // 0: {"name" => "xxx"} // 1: {"age" => 5} // size: {...} // } console.log(map.size); console.log(map.has("name")); console.log(map.get("age")); map.set("name", "zhangsan"); console.log(map); // { // 0: {"name" => "zhangsan"} // 1: {"age" => 5} // size: {...} // } ``` ## 模板字符串 ```js // 带标签的模板字符串 const foo = (a, b, c, d) => { console.log(a); console.log(b); console.log(c); console.log(d); }; const name = "xxx"; const age = 18; foo`这是${name},他的年龄是${age}岁`; // 打印: { // ["这是", ",他的年龄是", "岁", raw: Array(3)] // xxx // 18, // undefined // } ``` ## ES6 新增正则表达式修饰符 ES5 的正则修饰符:i(忽略大小写) m(多行匹配) g(全局匹配) ES6 新增:y(粘连修饰符),g 是每次匹配剩余的,y 是从剩余的第一个开始匹配 u: unicode 模式匹配 ## 数值的扩展 ```js // 十进制 -> 二进制 const a = 5; console.log(a.toString(2)); // 101 // 二进制 -> 十进制 const b = 101; console.log(parseInt(b, 2)); // 5 // ES6 0B二进制 0O八进制 const a = 0b101; console.log(a); //5 const b = 0o777; console.log(b); //511 ``` ## proxy ```js // 最简易的代理 let obj = {}; let p = new Proxy(obj, {}); p.name = "imooc"; console.log(obj.name); // 'imooc' for (let key in obj) { console.log(key); // 'name' } // get 拦截对象属性的读取,比如proxy.foo或proxy['foo'] let dict = { hello: "你好", world: "世界", }; dict = new Proxy(dict, { get(target, prop) { // target: // { // 'hello': '你好', // 'world': '世界' // }; // dict["world"] 时 prop 为 "world" // dict["xxx"] 时 prop 为 "xxx" return prop in target ? target[prop] : "error"; }, }); console.log(dict["world"]); // 世界 console.log(dict["xxx"]); // 'error' // set 拦截对象属性的设置,返回一个布尔值,比如proxy.foo=v,或数组的push、unshift等 let arr = []; arr = new Proxy(arr, { set(target, prop, val) { if (typeof val === "number") { target[prop] = val; return true; } else { return false; } }, }); arr[1] = 7; arr.push(5); console.log(arr[0], arr[1], arr[2], arr.length); // undefined 7 5 3 // has 拦截 proKey in proxy 的操作,返回一个布尔值 let range = { start: 1, end: 5, }; range = new Proxy(range, { has(target, prop) { return prop >= target.start && prop <= target.end; }, }); console.log(2 in range); // true console.log(9 in range); // false // ownKeys 拦截属性遍历包括 getOwnPropertyNames、getOwnPropertySymbols、keys、for……in, 返回一个数组 // 前面知识复习: let obj = { name: "imooc", [Symbol("es")]: "es6", }; console.log(Object.getOwnPropertyNames(obj)); // ['name'] console.log(Object.getOwnPropertySymbols(obj)); // [Symbol(es)] console.log(Object.keys(obj)); // ['name'] for (let key in obj) { console.log(key); // ['name'] } // ownKeys 使用: let userinfo = { username: "lyc", age: 34, _password: "***", }; userinfo = new Proxy(userinfo, { ownKeys(target) { return Object.keys(target).filter((key) => !key.startsWidth("_")); }, }); for (let key in userinfo) { console.log(key); // username age } console.log(Object.keys(userinfo)); // ['username', 'age'] // deleteProperty 拦截 delete proxy[proxyKey]的操作,返回一个布尔值 // apply 拦截函数调用、call 和 apply 操作 let sum = (...args) => { let sum = 0; args.forEach((item) => { num += item; }); return num; }; sum = new Proxy(sum, { apply(target, ctx, args) { return target(...args) * 2; }, }); console.log(sum(1, 2)); // 6 console.log(sum.call(null, 1, 2, 3)); // 12 console.log(sum.apply(null, [1, 2, 3])); // 12 // construct 拦截 new 命令,返回一个对象 let User = class { constructor(name) { this.name = name; } }; User = new Proxy(User, { construct(target, args, newTarget) { console.log("construct"); return new target(...args); }, }); console.log(new User("imooc")); ``` ## Reflect 1、将 Object 属于语言内部的方法放到 Reflect 上 ```js // Object 上的方法 Object.defineProperty(); // Reflect 上的方法 Reflect.defineProperty(); ``` 2、修改某些 Object 方法的返回结果,让其变得更合理 ```js // 原始方法判断某个对象的某个属性能否被定义 try { Object.defineProperty(); // 如果不能将报错 } catch (e) {} // 使用 Reflect if (Reflect.defineProperty()) { // 能否被定义将返回布尔类型的值,而不是报错 // bollean } else { } ``` 3、让 Object 操作变成函数行为 ```js // 原始写法判断 Object 里是否有 assign 方法 console.log("assign" in Object); // true // 使用 Reflect console.log(Reflect.has(Object, "assign")); // true ``` 4、Reflect 对象的方法与 Proxy 对象的方法一一对应 ## Promise ```js // 回调地狱改成 promise // callback hell ajax("static/a.json", (res) => { console.log(res); ajax("static/b.json", (res) => { console.log(res); ajax("static/c.json", (res) => { console.log(res); }); }); }); // promise new Promise((resolve, reject) => { // 请求 a.json ajax("static/a.json", (res) => { console.log(res); resolve(); }); }).then(res=>{ console.log('a 成功') return new Promise((resolve, reject) => { // 请求 b.json ajax("static/b.json", (res) => { console.log(res); resolve(); }); }).then(res=>{ console.log('b 成功') return new Promise((resolve, reject) => { // 请求 c.json ajax("static/c.json", (res) => { console.log(res); resolve(); }); }).then(res=>{ console.log('c 成功') }); // 优化 function getPromise(url){ return new Promise(resolve, reject){ ajax(url, res => { resolve(res) }) } } getPromise('static/a.json').then(res => { console.log(res) return getPromise('static/b.json') }).then(res => { console.log(res) return getPromise('static/c.json') }).then(res => { console.log(res) }) // promise.all const imgArr = ['1.jpg', '2.jpg', '3.jpg'] let promiseArr = [] imgArr.forEach(item => { promiseArr.push(new Promise(resolve, reject)=>{ // 图片上传的操作 resolve() }) }) Promise.all(promiseArr).then(res => { // 插入数据库的操作 console.log('图片全部上传完成') }) // 使用 promise.race 限制请求加载时间 function getImg(){ return new Promise((resolve, reject) => { let img = new Image() img.onload = function(){ resolve(img) } img.src = 'http://www.xxx.com/xxx.jpg' }) } function timeOut(){ return new Promise((resolve, reject) => { setTimeout(() => { reject('图片请求超时') }, 2000) }) } Promise.race([getImg(), timeOut()]).then(res => { console.log(res) }).catch(err => { console.log(err) }) ``` ## generator ```js function* gen(x) { let y = 2 * (yield x + 1); let z = yield y / 3; return x + y + z; } let g = gen(5); console.log(g.next()); // 6 console.log(g.next()); // NaN console.log(g.next()); // NaN let g = gen(5); console.log(g.newxt()); // 6 console.log(g.newxt(12)); // 8 y=24 console.log(g.newxt(13)); // 42 z=13 x=5 // 自增 7 的生成器 function* count(x = 1) { while (true) { if (x % 7 === 0) { yield x; } x++; } } let n = count(); console.log(n.next().value); // 7 console.log(n.next().value); // 14 console.log(n.next().value); // 21 console.log(n.next().value); // 28 console.log(n.next().value); // 35 // 使用生成器连续发送请求 function request(url) { ajax(url, (res) => { getData.next(res); }); } function* gen() { let res1 = yield request("static/a.json"); console.log(res1); let res2 = yield request("static/b.json"); console.log(res2); let res3 = yield request("static/c.json"); console.log(res3); } let getData = gen(); getData.next(); ``` ## Iterator 对于可迭代对象有两种情况: 1、可迭代协议:Symbol.iterator 2、迭代器协议: ```js // 把不可迭代的对象可迭代化 return { next() { return { value, done }; }, }; ``` 原生具备 Iterator 接口的数据结构: Array、Map、Set、String、TypedArray、函数的 arguments 对象、NodeList 对象 ```js function makeIterator(arr) { let nextIndex = 0; return { next() { return nextIndex < arr.length ? { value: arr[nextIndex++], done: false, } : { value: undefined, done: true, }; }, }; } let it = makeIterator(["a", "b", "c"]); console.log(it.next()); // {value: 'a', done: false} console.log(it.next()); // {value: 'b', done: false} console.log(it.next()); // {value: 'c', done: false} console.log(it.next()); // {value: undefined, done: true} // 数组原生的 iterator let arr = ["a", "b", "c"]; console.log(arr); let it = arr[Symbol.iterator](); console.log(it.next()); // {value: 'a', done: false} console.log(it.next()); // {value: 'b', done: false} console.log(it.next()); // {value: 'c', done: false} console.log(it.next()); // {value: undefined, done: true} // 让对象可迭代 let courses = { allCourse:{ frontend: ['ES', '小程序', 'Vue', 'React'] backend: ['Java', 'Python', 'SpringBoot'] webapp: ['Android', 'IOS'] } } courses[Symbol.iterator] = function(){ let allCourse = this.allCourse let keys = Reflect.ownKeys(allCourse) let values = [] return{ next(){ if(!values.length){ if(keys.length){ values = allCourse[keys[0]] keys.shift() } }return{ done:!values.length, value:values.shift() } } } } // 使用 for(let c of courses){ console.log(c) } // 使用 generator 实现 courses[Symbol.iterator] = function* (){ let allCourse = this.allCourse let keys = Reflect.ownKeys(allCourse) let values = [] while(true){ if(!values.length){ if(keys.length){ values = allCourse[keys[0]] keys.shift() yield value.shift() } else { return false } } else { yield values.shift() } } } ``` ## async 与 await ```js function timeout() { return new Promise((resolve) => { setTimeout(() => { console.log(1); resolve(); }, 1000); }); } // 使用 await 与不使用 await // 使用 await async function foo1() { await timeout(); console.log(2); // 先打印 1 后打印 2 } // 不使用 await async function foo2() { timeout(); console.log(2); // 先打印 2 后打印 1 } // 使用 async await 处理失败的 promise function timeout() { return new Promise((resolve, reject) => { setTimeout(() => { // resolve('success'); reject("fail"); }, 1000); }); } async function foo() { return await timeout(); } foo() .then((res) => { console.log(res); }) .catch((err) => { console.log(err); }); // async await 实现 axios 伪代码 async function request() { const data = await axios.get("http://xxx.com"); console.log(data); } // 使用 async await 实现 ajax 的异步操作按顺序执行 function request(url) { return new Promise((resolve) => { ajax(url, (res) => { resolve(res); }); }); } async function getData() { const res1 = await request("static/a.json"); console.log(res1); const res2 = await request("static/b.json"); console.log(res2); const res3 = await request("static/c.json"); console.log(res3); } getData(); ``` ## for await of ```js // 数组的同步迭代遍历 for……of const arr = ["es6", "es7", "es8", "es9"]; arr[Symbol.iterator] = function () { let nextIndex = 0; return { next() { return nextIndex < arr.length ? { value: arr[nextIndex++], done: false, } : { value: undefined, done: true, }; }, }; }; for (let item of arr) { console.log(item); } // 数组的异步迭代遍历 for await……of function getPromise(time) { return new Promise((resolve, reject) => { setTimeout(() => { resolve({ value: time, done: false, }); }, time); }); } const arr = [getPromise(1000), getPromise(2000), getPromise(3000)]; arr[Symbol.asyncIterator] = function () { let nextIndex = 0; return { next() { return nextIndex < arr.length ? arr[nextIndex++] : { value: undefined, done: true, }; }, }; }; async function test() { for await (let item of arr) { console.log(item); } } test(); // 1 秒后打印 1000 // 再隔 2 秒后打印 2000 // 再隔 3 秒后打印 3000 ``` ## 正则表达式 ```js // 具名组匹配 const reg = /(?\d{4})-(?\d{2})-(?\d{2})/; const groups = reg.exec("2020-02-01").groups; const { year, month, day } = groups; console.log(year, month, day); // 先行断言 const str = "ecmascript"; console.log(str.match(/ecma(?=script)/)); // 匹配后面是 script 的 ecma // 后行断言 console.log(str.match(/(?<=ecma)script/)); // 匹配前面是 ecma 的 script console.log(str.match(/(? val > 80); console.log(Object.fromEntries(res)); ``` ## 数组扁平化 ```js const arr = [1, 2, 3, [4, 5, 6, [7, 8, 9, [10, 11, 12]]]]; console.log(arr.flat(Infinity)); // arr.flat 传入的参数为扁平化层级 ``` ## 正则表达式的全局匹配 ```js const str = `
第一个div

这是p

第二个div
这是span
第三个div
`; // 使用正则对象的 exec g 匹配全部的 div function selectDiv(regExp, str) { let matches = []; while (true) { console.log(regExp.lastIndex); const match = regExp.exec(str); console.log(match); if (match == null) { break; } matches.push(match[1]); } return matches; } const regExp = /
(.*)<\/div>/g; // 不使用 g 模式匹配,会在每次匹配后重头开始匹配,导致 while 死循环 const res = selectDiv(regExp, str); console.log(res); // 字符串的 match 方式实现 console.log(str.match(regExp)); //['
第一个div
, '
第二个div
', '
第三个div
'] // 字符串的 replace 方式实现 function selectDiv(regExp, str) { let matches = []; str.replace(regExp, (all, first) => { matches.push(first); }); return matches; } const res = selectDiv(regExp, str); console.log(res); // ['第一个div, '第二个div', '第三个div'] // 字符串的 matchAll 方式实现 function selectDiv(regExp, str) { let matches = []; for(let match of str.matchAll(regExp)){ matches.push(match[1]); }); return matches; } const res = selectDiv(regExp, str) console.log(res); // ['第一个div, '第二个div', '第三个div'] ``` ## Promise.allSettled ```js Promise.allSettled([ Promise.resolve({ code: 200, data: [1, 2, 3], }), Promise.reject({ code: 500, data: [], }), Promise.resolve({ code: 200, data: [7, 8, 9], }); ]).then(res=>{ const data = res.filter(item => item.status === 'fulfilled') console.log(data) }) ``` ## vue 实战 ```js async created(){ const {data} = await axios.get('http://www.xxx.com') // 对数据的升序降序进行代理 this.proxy = new Proxy({},{ get(target, key){ if(key === 'asc'){ // 升序 return [].concat(data).sort((a, b) => a.name > b.name ? 1 : -1) }else if(key === 'desc'){ // 降序 return [].concat(data).sort((a, b) => b.name > a.name ? 1 : -1) }else{ return data } }, set(){ return false } }) this.userLst = this.proxy.data.default }, methods:{ asc(){ this.userList = this.proxy.asc }, desc(){[].concat(data this.userList = this.proxy.desc }, reset(){ this.userList = this.proxy.default } } ``` **多图片上传到云存储:** ```html

提示:一次可选择多张图片,最多不超过9张(单张大小 < 1M)

``` ## webpack 初探 **1、Loader:** loader 让 webpack 能够去处理其他类型的文件,并将它们转换为有效模块 ```js module.exports = { module: { rules: [ { test: /\.txt$/, use: "raw-loader", }, ]; } } ``` **2、Plugin:** loader 用于转换某些类型的模块,而插件则可以用于执行范围更广的任务,比如打包优化、资源管理、注入环境变量等 ```js const HtmlWebpackPlugin = require("html-webpack-plugin"); // 用于为 html 文件自动引入外部资源 const webpack = require("webpack"); // 用于访问内置插件 module.exports = { plugins: [ new HtmlWebpackPlugin({ template: "./src/index.html", }), ], }; ``` 对某一个目录下的文件不进行 webpack 打包编译,直接拷贝过去: ```js const copyPlugin = require("copy-webpack-plugin"); module.exports = { plugins: [ new copyPlugin([ { from: "source", to: "dest" }, // 从 source 目录原方不动的拷贝到 dest 目录下 { from: "other", to: "public" }, // 从 other 目录原方不动的拷贝到 public 目录下 ]), ], }; ``` ## webpack 优化配置 package.json: ```json "scripts":{ "start": "webpack-dev-server --mode=development --config ./build/webpack.config.js", "build": "webpack --mode=production --config ./build/webpack.config.js" } ``` webpack.config.js: ```js const merge = require("webpack-merge"); const baseConfig = require("./webpack.base.config.js"); const devConfig = require("./webpack.dev.config.js"); const proConfig = require("./webpack.pro.config.js"); module.exports = (env, argv) => { // 此处的 argv 参数需要在 package.json 中传入 const config = argv.mode === "development" ? devConfig : proConfig; return merge(baseConfig, config); }; ``` webpack.base.config.js: ```js module.exports = { module: { rules: [ { test: /\.m?js$/, exclude: /(node_modules|bower_components)/, use: { loader: "babel-loader", options: { presets: [ [ "@babel/preset-env", { useBuiltIns: "entry", }, ], ], }, }, }, ], }, }; ``` webpack.dev.config.js: ```js module.exports = { devtool: "cheap-module-eval-source-map", }; ``` webpack.pro.config.js: ```js const { CleanWebpackPlugin } = require("clean-webpack-plugin"); module.exports = { plugins: [new CleanWebpackPlugin()], }; ```