[TOC] > ## :-: [Babel - 官网](https://www.babeljs.cn/) ``` // ES6 转 ES5 ----- 下载插件、 // cnpm install @babel/core // cnpm install @babel/preset-env // cnpm install @babel/cli // 配置文件 --- .babelrc // { // "presets": [ // "@babel/preset-env" // ] // } // 执行 // npm babel es6.js -o new-es5.js ``` > ## :-: [ECMAScript 6 入门](http://es6.ruanyifeng.com/) > ## :-: ES6 - 点点点运算符 ``` // ...arr --- 收集 function sum(...arg) { // ...arg // arg == arguments 并将类数组转化为数组了、 let sumNumber = 0; arg.forEach(function(ele) { sumNumber += ele; }); return sumNumber; } console.log( sum(1, 2, 3, 4, 5, 6) ); // 21 function sum(a, b, ...arg) { console.log(a, b, arg) } sum(1, 2, 3, 4, 5); // 1 2 [3, 4, 5] // ...arr --- 展开 let arr = [1, 2, 3]; (function(a, b, c) { console.log(a, b, c) }( ...arr )); // 1 2 3 let arr = [1, 2, 3] console.log(...arr); // 1 2 3 let arr1 = [1, 2, 3], arr2 = [4, 5, 6], newArr = [...arr1, ...arr2] console.log(newArr); // [1, 2, 3, 4, 5, 6] // 在ES7中,支持对象浅层克隆、兼容不好 let obj_1 = { name: 'aaa', are: 18, arr: [1, 2, 3] } let obj_2 = { name: 'bbb', test: 666, obj: { a: 1, b: 2, c: 3 } } let newObj = {...obj_1, ...obj_2, test: 'hi~' } console.log(newObj); ``` > ## :-: ES6 - 结构化赋值 ``` let obj = { a: 1, b: 2, c: 3 } let { a, b, c } = obj; console.log(a, b, c); // 1 2 3 let { a: aa, b: bb, c: cc } = obj; console.log(aa, bb, cc); // 1 2 3 // 默认赋值 (很常见) let { d: dd = 100 } = obj; console.log(dd); // 100 function sum(a = 1, b = 2) { console.log(a, b) } // 解构数组 let arr = [1, 2, 3] let { 0: x, 1: y, 2: z } = arr; console.log(x, y, z); // 1 2 3 let [x, y, z] = arr; console.log(x, y, z); // 1 2 3 let [, , z, s = 5] = arr; console.log(z, s); // 3 5 ``` > ## :-: ES6 - 箭头函数 ``` // 箭头函数特点: // 1、不用写function关键字 // 2、只能作为函数使用不能new,没有原型 // 3、参数不能重复命名 // 4、返回值可以不写return,但是有时需要配合{} // 5、内部arguments this由定义时外围最接近一层的非箭头函数的arguments和this决定其值。 let fn = (a, b, c) => { console.log(a, b, c) } fn(1, 2, 3); // 1 2 3 // 省略 return let fn = (a, b) => a + b; fn(5, 10) // 15 // 更加精简的写法、 let sum = x => y => z => x + y + z; sum(1)(2)(3); // 6 // 箭头函数没有arguments,会向上找(function) function demo() { let test = (...arg) => { console.log(arguments); // [1, 2] console.log(arg); // [3, 4] }; test(3, 4); } demo(1, 2); // —— 技巧篇 let obj = { a: 0, fn() { // 箭头函数this为外围function的this,箭头函数没有原型链、 setInterval(() => { console.log(++this.a) }, 500); } } obj.fn(); let arr = [1, 5, 8, 6, 7, 2, 4, 3] arr.sort( (a, b) => a - b ); // [1, 2, 3, 4, 5, 6, 7, 8] arr.filter( ele => ele > 5 ); // [6, 7, 8] ``` > ## :-: Object.defineProperty ``` // 在对象上定义一个新的、具有详细描述的属性。或者修改一个对象的现有属性、 // Object.defineProperty(对象,属性,描述符); 返回值:修改后的对象、 let obj = {} Object.defineProperty(obj, 'name', { // 数据描述符(不共存): // value -- 属性值 value: 'cst', // writable -- 是否可修改(默认false) // 演示:obj[name] = 'test'; writable: true, // configurable -- 是否可配置(默认false) // 演示:delete obj[name]; configurable: true, // enumerable -- 是否可枚举(默认false) // 演示:for (let prop in obj) { console.log( obj[prop] ) } enumerable: true, // 存取描述符(不共存): get: function() { // 当obj[name]被读取时调用该方法,劫持后返回 'get' return 'get'; }, set: function(val) { // 对象属性赋值时会经过这个方法,属性值通过val参数传入、 return val; }, }) ``` ``` // 简写形式 let newObj = { tempValue: 'test', get name() { return this.tempValue; }, set name(newValue) { this.tempValue = newValue; } } console.log( newObj.name ); ``` ``` // 注意:如果描述符中同时出现,value、writable 和 set、get两组的话,会冲突。切记不要同时使用。 // 作用:双向数据绑定的核心方法,主要做数据劫持操作 (监控属性变化) ,同时是后期ES6中很多语法糖底层实现核心的方法。 ``` > ## :-: ES6 - 数据劫持 (2019-6-15) ``` // 将对象的属性名打包成数组、 let obj = { a: 1, b: 2, c: 3 } console.log( Object.keys(obj) ); // ["a", "b", "c"] Object.keys(obj).forEach((key) => { console.log(key) }) ``` ``` // 原对象 let oData = { val: 'test' }, // 代理对象 // new Proxy(obj, {···}) -- 植入代理模式的思想,以简洁易懂的方式控制对外部对象的访问、Proxy 对象用于定义基本操作的自定义行为(如属性查找,赋值,枚举,函数调用等)。 oProxyData = new Proxy(oData, { set(target, key, value, receiver) { // target -- 原对象 key -- 属性名 value -- 属性值 receiver -- 代理 console.log(target, key, value, receiver); // 等同于:target[key] = value; Reflect.set(target, key); }, get(target, key, receiver) { // target -- 原对象 key -- 属性名 receiver -- 代理 console.log(target, key, receiver); // 等同于:return target[key]; return Reflect.get(target, key); }, // ··· }); console.log(oProxyData.val); // 'test' ``` > ## :-: ES6 - class定义构造函数 (2019-6-16) ``` // Object.setPrototypeOf(obj, prototype) -- 设置对象的原型。obj : 要设置其原型的对象。prototype : 该对象的新原型(一个对象 或 null)。 // Object.setPrototypeOf(AttackPlane.prototype, Plane.prototype); // 相当于:AttackPlane.prototype.__proto__ = Plane.prototype; // Object.create(proto, [propertiesObject]) -- 创建一个新对象,使用现有的对象来提供新创建的对象的原型,proto : 必须,新建对象的原型对象。propertiesObject : 可选,添加到新创建对象的可枚举属性。 // AttackPlane.prototype = Object.create(Plugin.prototype); Class与普通构造函数有何区别? 1、class在语法上更贴近面向对象的写法。 2、class实现继承更加易读易理解。 // class -- 定义一个构造函数,声明创建一个基于原型继承的具有给定名称的新类。 class Plane extends New { // Plane 继承自 New 构造函数、 constructor(name) { // Plane super(name); // 相当于:New.call(name); this.name = 'abc'; }; // Plane.prototype test() { // test 为原型上的普通函数、 console.log('test'); }; // static abc = 123; // 在ES6中只能添加方法,不能添加普通的属性(会报错)、ES7才能添加(不能直接加) } console.log( new Plane('new') ); ``` ``` // throw 'Error' -- 主动报错 // object instanceof Element -- instanceof 可以在继承关系中用来判断一个实例是否属于它的父类型 ``` ``` // class -- ES7·定义一个构造函数 class Plane { abc = 123; // ES7 私有属性的定义方式,跟constructor中this.abc一样、 constructor(name) { this.name = 'abc'; }; // Plane.prototype static abc = 123; // 静态属性会被定义在原型上、 test() { // test 为原型上的普通函数、 console.log('test'); }; } console.log( new Plane('new') ); ``` > ## :-: ES6 - Set / Map (2019-6-19) ``` // Set -- 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。 // 参数:如果传递一个可迭代对象,它的所有元素将不重复地被添加到新的 Set中。如果不指定此参数或其值为null,则新的 Set为空。 // [] '' arguments NodeList // 特点:成员值去重 let oS = new Set([1, 2, 3, [1, 2], true, { name: 'cst' }, 1, 2, true, 4]); let oStr = new Set('12'); // Set {"1", "2"} oStr.add(3); // 添加成员:Set {"1", "2", 3} // .delete() -- 删除成员、 // .clear() -- 清除 // .has() -- 判断 // .forEach() -- 遍历 oStr.forEach(ele => { console.log(ele); }); // ES6 of 遍历 for (let prop of oStr) { console.log(prop); } // 转换 -- Set -> [] let arr = [1, 2, 3, 1, 2]; let oArr = new Set(arr); // 将数组类型转为Set类型 Set {1, 2, 3} // ··· Array.from Array.from(oArr); // 将Set转为数组类型 [1, 2, 3] [...oArr] // 将Set转为数组类型 [1, 2, 3] let arr1 = new Set([1, 2, 3, 1, 2]), arr2 = new Set([2, 3, 4, 5, 5]), // 取并集 oArrS = new Set([...arr1, ...arr2]); // Set {1, 2, 3, 4, 5} // 取交集 let intersectionArr = [...arr1].filter( ele => arr2.has(ele) ); // [2, 3] // 取差集 ( arr1有arr2没有的值 ) [...arr1].filter( ele => !arr2.has(ele )); // [1] [...arr2].filter( ele => !arr1.has(ele )); // [4, 5] ``` ``` // Map -- 对象保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值。 let oMp = new Map( [ ['name','cst'],['age',18],['sex',true] ] ); console.log(oMp); // Map {"name" => "cst", "age" => 18, "sex" => true} // api // 设值 -- oMp.set('name', 'cst'); // 取值 -- oMp.get('name'); // 删除 -- oMp.delete('name'); // 清空 -- oMp.clear(); // 判断 -- oMp.has('name'); // 长度 -- oMp.size // 将所有属性名打包成数组 -- oMp.keys(); oMp.forEach((ele, key) => { console.log(ele, key) }); ``` ``` // lodash.js https://www.lodashjs.com <script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js" integrity="sha256-7/yoZS3548fXSRXqc/xYzjsmuW3sFKzuvOCHd06Pmps=" crossorigin="anonymous"></script> ``` > ## :-: ES6 - Promise (2019-6-26) ``` // Promise -- 对象用于表示一个异步操作的最终状态(完成或失败),以及该异步操作的结果值。 语法:new Promise( function(resolve, reject) {...} /* executor */ ); // node.js let fs = require('fs'); fs.readFile('./Untitled-1.txt', 'utf-8', (err, data) => { console.log(data); }); // ——————————————————————————————————————————————————————————————————————————————————————————————— // 并发回调、 const Store = { list: [], times: 3, subscribe() { this.list.push(func); }, fire(...arg) { --this.times == 0 && this.list.forEach((ele) => { ele.apply(null, arg) }); } }; // ——————————————————————————————————————————————————————————————————————————————————————————————— // Promise.all // executor function 同步执行 // Promise -- 承诺 let oP = new Promise((resolve, reject) => { // 异步操作 setTimeout(() => { Math.random() * 100 > 60 ? resolve('ok') : reject('no'); }, 1000); }); // then -- 成功,失败 oP.then((val) => { console.log(val); // throw new Error('-- 主动报错'); // return "返回值会作为下一次then的参数,并且重新调佣 resolve('ok') : reject('no') 方法"; // 返回Promise可以指定下一次then,是执行 resolve() 或者 reject() 。 return new Promise((resolve, reject) => { reject('2-no'); }); }, (val) => { console.log(val); return "返回值会作为下一次then的参数,并且重新调佣 resolve('ok') : reject('no') 方法"; }).then((val) => { console.log('ok then-2: ' + val); }, (val) => { console.log('no then-2: ' + val); }); ``` ``` // Promise let oP = Promise.resolve("ok"); // 直接调佣成功的回调 let oP = Promise.reject("no"); // 直接调佣失败的回调 oP.then( (val)=>{ console.log(val) },(reason)=>{ console.log(reason) } ); // .finally -- 无论成功、失败都会调用该方法。(没有参数) oP.finally( ()=>{ console.log("over") } ); ``` ``` const fs = require('fs'); function readFile(path) { return new Promise((res, rej) => { fs.readFile(path, 'utf-8', (err, data) => { if (data) { res(data); } }) }) } Promise.all([readFile('./data/1.txt'), readFile('./data/2.txt'), readFile('./data/3.txt')]) // 全部触发成功时、触发 then .then((val) => { console.log(val); // Array(3) ["111", "222", "333"] }); // 更多方法、 // Promise.all(iterable); // Promise.race(iterable); ``` > ## :-: ES6 - Iterator(迭代器) (2019-6-28) ``` // Iterator -- 迭代器 function OuterIterator(o) { let curIndex = 0; let next = () => { return { value: o[curIndex], done: o.length == ++curIndex } } return { next }; } let arr = ['a', 'b', 'c']; let oIt = OuterIterator(arr); oIt.next(); // Object {value: 1, done: false} oIt.next(); // Object {value: 2, done: false} oIt.next(); // Object {value: 3, done: true} oIt.next(); // Object {value: undefined, done: false} // ES6 - 遍历数组 for (let ele of arr) { console.log(ele); } ``` ``` let obj = { 0: 'a', 1: 'b', 2: 'c', length: 3, // [Symbol.iterator]: function() { // let curIndex = 0; // let next = () => { // return { // value: this[curIndex], // done: this.length == ++curIndex // } // } // return { // next // } // }, [Symbol.iterator]: function*() { let curIndex = 0; while (curIndex != this.length) { yield this[curIndex++]; } } } console.log([...obj]); // ["a", "b", "c"] ``` ``` // Generator 生成这个迭代对象 生成器函数 function* test() { yield 'a'; yield 'b'; yield 'c'; return 'abc'; } let oG = test(); oG.next(); oG.next(); oG.next(); ``` > ## :-: node.js - 四行代码写服务器 (2019-6-28) ``` // npm install express // express -- express框架 let express = require('express'), app = new express(); // 设置静态文件路径、 app.use(express.static('./page')); // 设置端口号大于8000、等于80 app.listen(12306); // 地址:127.0.0.1:12306 ``` > ## :-: [ES6模块化 导入|导出](https://www.jianshu.com/p/513ccffd3ced) (2019-7-8) ``` <!-- module -- 标记当前引入的文件为模块 --> <script type="module" src="./src/entrance.js"></script> // —————————————————————— './m1.js' let a = 0, b = 20, c = "default", d = a => { a = "demo"; console.log(a); } setInterval(() => { a++ }, 1000); function test() { console.log(a) } // export { a as name }; // 导出多个变量 export { a, b, c, d, test }; // 默认导出 export default c; // —————————————————————— './entrance.js' // node commonJs AMD CMD // -- ES6模块化 // import -- 导入 export -- 导出 // import引入是同步加载的、 // 导入的变量只能读不能取、导入的变量数据是实时绑定,同步的、 import default_1, { a as a1, b as b1, c as c1, d, test } from "./m1.js"; import default_2 from "./m1.js"; import * as all from "./m1.js"; console.log(all, default_1, a1, default_2); setInterval(() => { // 导出的变量数据是实时绑定的、 console.log(a1); }, 1000); let btn = document.getElementsByTagName("button")[0]; btn.onclick = () => { // 模块导入,按需加载、import() 方法的返回值是Promise对象(异步)、 // ({ test }) == 解构赋值、 import ("./m1.js") .then( ({ test }) => { console.log("val: ", test) }) .catch( err => { console.log("err: ", err) }); }; ``` > ## :-: 模板字符串 - [String对象方法](https://www.runoob.com/jsref/jsref-obj-string.html) (2019-7-8) ``` let str = "es"; console.log(`t${str}t`); // 'test' // 字符串方法 str = "String method"; // 查找字符串中是否包含指定的子字符串。true/false str.includes("String"); // true // 返回某个指定的字符串值在字符串中首次出现的位置。 str.indexOf("method"); // 7 ```