ES6 从6入门到10放弃(耐心)
语法本身并不重要,怎么解决问题!怎么更好的解决问题才是本质
ES6 --> ES7、8、9、10 利用新技能拓宽解决问题的思路
全新的JavaScript体系
字符串模板(直接赋值变量,支持表达式)
监听数据
自定义数据结构,遍历
ES7 --> ES10 全新体系,改变JS书写习惯
学习方法
- 体验乐趣 1天
- 进入状态 10天
- 养成习惯 1个月后
- 收获知识 3个月后
- 行程思维习惯 5个月后
ES6 基础语法 _作用域
Let & Const
全局作用域
var abc = 1234 (全局变量) abcd = 2345 (全局作用域)(作为window属性使用,可被删除) window.delete abcd // true
函数作用域 - 块状作用域
function test(){ var a = 3 函数作用域 if(true){ 块状作用域 } function test2(){ var b = 4 let c = 4 // let 当前{}块状作用域 return a + b } //作用域链,向上找 test2() 函数作用域 }
动态作用域
window.a = 3 function test(){ console.log(this.a) } // this 动态作用域变量 test() test.bind({a:100})()
Const 常量
const a a = 3 const a = 3 a = 4 // two error example
附加阅读
- 什么是作用域
- JavaScript 词法作用域 和 动态作用域
- 深入理解JS中声明提升、作用域链和this关键字
数组 _遍历 _转换 _生成 _查找
- ES5中有多少种遍历的方法?
优势缺点?数组? object?
const arr = [1,2,3,4,5] // 第一种 for(let i=1,i<=arr.lenght,i++){ console.log(arr[i]) } // 第二种 不支持 break,continue arr.foreach(function item(){ console.log(item) }) // 第三种 可return false 跳出循环 arr.every(function item(){ console.log(item) return true }) // 第四种 for in (瑕疵:为对象而设计) arr.8 = 6 for (let index in arr) { if(index === 2){ continue; //不会起作用 === 既检查值,也检查类型 } if(index * 1 === 2){ continue; // 起作用,index转换为数值类型 } if(index == 2){ continue; // 起作用 == 只检查值,不检查类型 } // 所以index是字符串类型 console.log(index, arr[index]) } continue,break
Ps: 数组是对象,数组是可遍历的。
for in 的缺点
- ES6 遍历方法
ES6中有多少种遍历的方法?
// for of 优点:可遍历自定义数组,缺点是什么?? for (const item of arr) { console.log(item) }
Array.from
ES5 将伪数组转换为数组的方法 例如 nodelist (遍历所有Dom)
ES6 如何转换?
// ES5 转换方法 // 转换arguments --> Collection let args = [].slice.call(arguments) // 找到所有img图片 --> NodeList let imgs = [].slice.call(document.querySelectorAll['img']) // ES6 方法 Array.prototype.from let args2 = Array.from(arguments) let imgs2 = Array.from(document.querySelectorAll['img']) // example 创建一个集合 长度5 内容为1 // ES5 写法 let arrs = Array(5) for(let i = 1, len = arrs.lenght ; i < len ; i++){ arrs[i] = 1 } // ES6 Array.from(arrayLike,mapFn,thisArg) // arrayLike 伪数组 含有lenght属性的对象就可以称为伪数组 例如 {'a':1,'b':2,lenght:2} let arrs = Array.from({lenght:5},function (){return 1})
Array.of-fill
ES5 创建一个新数组改怎么做
ES6 如何实现?
// ES5 新建数组 let arrs = Array(5) let arrs = ['',''] arrs.push(); // ES6 [from,of,fill]方法 let Array = Array.of(1,2,3,4,5) // Array.prototype.fill 填充数组 Array.from 升级版 // Array.fill(value,start,end) let arrs = Array(5).fill(5) // 修改数组 Array.fill(4,2,4)
Find & FindIndex
ES5 如何查找一个元素
ES6 的查找方法?
// ES5 的查找元素方法 filter 拿到所有返回符合条件的元素 // 没有验证是否存在某个元素的方法 let find = arrs.filter(function (item){ return item === 2 }) console.log(find) // ES6 的查找方法 // 有符合条件的元素,返回该元素,满足条件的第一个值 // 无符合条件,返回undefind let find = arrs.find(function (item){ return item === 2 }) // Array.prototype.findindex // 返回索引 let find = arrs.findIndex(function (item){ return item === 2 })
- 思考
- JavaScript 中有哪儿些元素是可以遍历的
- 如何给数据结构自定义遍历
- find() 和 ES5_fillter() 有什么区别
- 附加阅读
- 数组 Array
Class 类 _声明 _属性 _方法 _继承
ES5 中如何声明一个类
ES6 声明类的方法
Ps: 按照java类的定义,更容易理解,ES6就是对ES5类的语法糖,并未更改其本质行为。
//ES5 方法,声明一个类(当成一个构造函数去使用) let Animal = function(type){ this.type = type this.eat = function(){ console.log('eat food') } } // 实例对象 let dog = new Animal('dog') let cat = new Animal('cat') dog.eat = function (){ console.log('error') } dog.eat(); cat.eat(); // 违背继承原则,只能改变自己 // 优化,把eat方法挂载到实例链上 let Animal = function(type){ this.type = type } Animal.prototype.eat = function(){ console.log('i eat food') } // 子类修改父类方法 dog.constructor.prototype.eat = function(){ console.log('error') } // ES6 方法,如果理解不了原型链的写法,直接用es6的类即可 class Animal { constructor(type){ this.type = type } eat(){ Console.log('i eat food') } } let dog = new Animal('dog') let cat = new Animal('cat') dog.eat() // 何如看出es5 与 es6类的区别(class与es5使用原型链生成的类 区别就是语法糖,没区别!) console.log(typeof Animal) // result type is function
Setter & Getter (如何读写属性)
//ES5 无法实现读写属性 //闭包的方式,实现私有属性 _age let _age = 4 class Animal { constructor(type){ this.type = type } // 方法 eat(){ Console.log('i eat food') } // setter getter // age 为属性,不是方法 get age (){ return _age } set age(val){ if(){ // 满足条件赋值私有属性 _age = val }else{ // 控制setter } } } let dog = new Animal('dog') dog.age = 8 console.log(dog.age)
Static Methods 静态方法
- 对象实例的方法
- 类的静态方法
//ES5 静态方法 let Animal = function(type){ this.type = type } //ES5 实例方法,挂载在原型链上 Animal.prototype.eat = function(){ Animal.walk() Console.log('i eat food') } //ES5 静态方法 不是挂载在原型链上的,而是挂载在类上 Animal.walk = function(){ console.log('i m walking') } //ES6 静态方法 class Animal { constructor(type){ this.type = type } // 方法 eat(){ // 引用静态方法 Animal.walk() Console.log('i eat food') } // setter getter // age 为属性,不是方法 get age (){ return 4 } set age(val){ this.realage = val } static walk (){ console.log('i m walking') } }
Sub Classes 继承类
ES5 如何继承一个类
ES6 如何实现
Ps: 面向对象 之所以强大,就是因为继承 : )
//ES5 继承方法(其中一种方法) let Dog = function () { //初始化父类的构函数 //用call 是改变 this 的指针 // dog 就是父类的参数 Animal.call(this, 'dog') this.run = function () { console.log('i cant run') } } //把原型链指向父类的原型链 //值类型 引用类型 //不指向无法获取父类原型链上的方法 Dog.prototype = Animal.prototype //ES6 继承方法 (语法糖) Class Dog extends Animal { //构造函数 //显示 隐示 constructor(type) { super(type) this.age = 8 } } let dog = new Dog('type') dog.eat()
附加阅读
类
ES6 Class
函数 _默认值 _形参 _箭头函数
函数的默认值
ES5中怎么处理函数处理的默认值
ES6 处理函数默认值
//参数默认值 function f(x, y, z) { if (y == undefined) { y = 7 } if (z == undefined) { z = 7 } return x + y + z; } console.log(f(1, 2)) //ES6 function f(x, y = 7, z = 8) { //consolo.log(argu) return x + y + z } console.log( f(1,undefined,43) )
函数不确定参数的处理
ES5 中使用argments处理不确定参数
ES6 无法使用,如何处理
// 1 可以用arguments获取所有参数 // 2 arguments是伪数组,可以用原型链call对它进行遍历 function sum() { let num = 0 // ES5的获取方法 Array.prototype.forEach.call(arguments.forEach(item) { num += item * 1 }) // ES6 Array.from(arguments.forEach(item) { num += item * 1 }) console.log(sum(12, 3, 4, 5)) } //ES6 无法使用,如何处理 //... Rest parameter 代表所有参数都存在于nums中 function sum(...nums) { let num = 0 nums.forEach(function (item) { num += item * 1 }) return num } console.log(sum(1, 2, 3)) //Rest参数(...) 是获取所有参数 //...nums 是数组,不是伪数组 //输入参数,可以拆开,把所有不确定参数放于Rest数组里 function sum(base, ...nums) { let num = 0 nums.forEach(function (item) { num += item * 1 }) return base * 2 + num } console.log(sum(1, 2, 3))
Rest数组的逆运算 spread
//参数确定,入参为不确定的数组 let data = [1,2,3] function sum(x=1,y=2,z=4){ return x+y+z } //ES5 sum.apply(this,data) //ES6写法 spread 操作 sum(...data)
!箭头函数 ( ) => {}
//ES6箭头函数 ( 参数 )=>{ 函数体 } //无function关键字 let hello = (name) => { console.log('this is a function' + name) } //有且只有一个参数的时候,()可以省略 //无参不可省略() let hello = name => { console.log('this is a function' + name) } // 1.如果返回一个表达式 {}及return可以省略 let sum = (x, y, z) => x + y + z sum(1, 2, 3) // 2.如果返回一个对象,需要在函数体加小括号({ }) // 小括号的含义??? let sum = (x, y, z) => ({ x: x, y: y, z: z }) // 无法理解,可按这种方式书写 let sum = (x, y, z) => { return { x: x, y: y, z: z } } // ES5中 谁调用this,就指向谁 // 箭头函数的 this let test ={ name : 'test' say : function(){ console.log(this.name) } } test.say() //指向test // 在ES6中,this指向谁? let test ={ name : 'test' say : () => { console.log(this.name) } } console.log(test.say()) //指向window
练习
- 如何用箭头函数实现一个数组的排列
- 箭头函数对this的处理 还有什么作用
阅读
箭头函数
默认参数值
Three dots ( … ) in JavaScript
Three dots ( … ) in JavaScript https://dev.to/sagar/three-dots---in-javascript-26ci
对象 Object
Object Property
ES5 中object属性可以简写吗?
ES6 可以吗
let x = 1,y=2,z=3 let obj = { a:x, b:y, hello:function(){ console.log('hello') } //ES5不允许增加异步函数 } //ES5 对象增加元素 obj[z]=5 //ES6 key支持变量和表达式 let obj = { x, y, [z]:5, hello(){ console.log('直接写hello() ') } //ES6 新增 可以在obj中增加异步方法 * hello2(){ console.log('直接写hello() ') } } //异步函数 function* functionName(){ }
Set数据结构
// 使用方法 增删改查 改:先删 后增 靠谱~ let s = new Set() s.add('one') s.delete('one') s.forEach(item =>{ console.log(item) }) for (let item of s) { console.log(item) }
Map数据结构
// 字典 传入可遍历对象 entry object // key可以是任意值 let map = new map() // 新增 map.set(1,2) map.set(2,3) // 修改 map.set(1,3) map.delete(1) map.clear() //清空 map.size //长度 map.has(1)//boolean map.get(1)//返回value // map 遍历 先value 后key map.forEach((value,key)=>{ console.log(value,key) }) // forof 只能遍历 可遍历对象! for (let [key,value] of map) { console.log(key,value) } // map 键的类型可以是任意的 let o = ()=>{ console.log('0') } map.set(o,4) // 性能 Map > Object
Object.assign
把一个对象拷贝到另外一个对象
//ES5拷贝对象的方法,遍历循环赋值 //ES6使用新增API Object.assign(target,source) //缺陷: 浅复制 (引用类型会丢失原始数据) target 对象 source 对象
思考
- 如果源对象或者目标对象参数为undefind或者null,会发生什么?
- WeakSet,WeakMap,Set,Map (同样的API) 有什么区别
正则 RegExp
Y修饰符
//正则表达式 // g会跳字节匹配 只要可以匹配到 const a = 'aaaa_aa_a' const r1 = /a+/g const r2 = /a+/y console.log(r1.exec(a)) console.log(r2.exec(a)) //sticky 粘连的语法,会连续匹配 console.log(r1.exec(a)) console.log(r2.exec(a))
U修饰符
ES5如何用正则处理中文呢
ES6升级了什么
//unicode 需要深入了解字符编码 例如我的名字 '吉'的异形字 𠮷 unicode编码为 U+20BB7 let s = '𠮷' let s2 = '\uD842 \uDFB7' // ES5 s是否为字符,返回false console.log(/^.$/.test(s)) // 加U返回 true console.log(/^.$/u.test(s)) // true console.log(/^\uD842/.test(s2)) // false console.log(/^\uD842/u.test(s2)) // 加u 可以使用unicode编码值来正则匹配字符 const a = 'a' console.log( /^\u{61}/u.test('a')) 总结: 遇到中文,加U没错~
阅读
unicode及编码方式概述 https://www.ibm.com/developerworks/cn/java/unicode-programming-language/index.html
Unicode与JavaScript详解 https://coding.imooc.com/lesson/389.html#mid=29198
Template
字符串
字符串换行、包含变量表达式、包含逻辑运算符如何处理
ES6 有更好的办法吗
const a = 20 const b = 10 const c = 'javascript' //es5 const str = 'my age is ' + (a + b) + 'i hate' + c //es6 拼接 const str = `my age is ${a+b} and i hate ${c}` // 字符串模板 const retailPrice = 20 const wholeSalePrice = 16 let showTxt = '' let type = 'retail' if (type = 'retail') { showTxt = "您购买产品的单价为:" + retailPrice } else { showTxt = "您购买产品的批发价为:" + retailPrice } console.log(showTxt) //ES6 使用Tag 函数,字符串模板 let Price = (Strings, type) =>{ let s1 = Strings[0] const retailPrice = 20 const wholeSalePrice = 16 let showTxt if (type = 'retail') { showTxt = "单价为:" + retailPrice } else { showTxt = "批发价为:" + retailPrice } return `${s1}${showTxt}` } let showTxt = Price`您购买产品的${retail}` console.log(showTxt) //字符串换行 let s = `我是第一行 我是第二行` console.log(s)
- 附加阅读
- 模板字符串
Destructure
从一个复杂的数组中提取数据
let arr = ['s1', 's2'] let [n1, n2] = arr console.log(n1, n2) // Array || Object let arr = ['a', 'b', 'c', 'd'] let [n1, , , n4] = arr // 字符串为什么可以 let arr = 'abcd' // 左边等式必须为中括号 let [n1, , , n4] = arr // 右边为 所有可遍历的对象 let [n1, , , n4] = new Set([1,2,3,4])
给对象的属性重新赋值
let user = [name: 'name', surname: 'sname'] //对象属性赋值 [user.name, user.surname] = [1, 2] console.log(user) //隐式赋值 //[k,v]也是一种解构赋值 for (const [k, v] of Object.entries(user)) { console.log(k, v) } // 未赋值的数据去哪儿了? // 根据浏览器垃圾回收机制,长时间未使用的数据会被回收 let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9] let [one, two] = arr // arr里如果无数据,one two为undefind // 剩下的变量赋值进others let [one, two,...others] = arr
Object 解构赋值
// 复杂 Object 解构赋值 let options = { style: { width: '200', height: '200', }, other: 'shi', item: ['item1', 'item2'] } let { style: { width, height }, other, item[item1, item2] } = options console.log(width,height,item1)
- 推荐阅读
- 解构赋值
异步操作
Promise
// Promise // ES5异步加载 function loadScript(src, callback) { let script = document.createElement('script') script.src = src script.onload() = () => { callback() } document.head.append(script) } function test() { console.log('test') } // ES5的回调地狱 a>b->c->d // 回调地狱 loadScript('1.js', function () { loadScript('2.js', function () { loadScript('3.js', function () { }) }) }) // 使用ES6 异步操作 // 执行 Promise pending状态为undefind // pending 状态为不可逆的 function loadScript(src) { return new Promise((resolve, reject) => { let script = document.createElement('script') script.src = src script.onload() = () => resolve() // fulfilled result script.onerror() = () => reject() // rejected error document.head.append(script) }) } loadScript('./1.js') .then(loadScript('./2.js')) .then(loadScript('./3.js'))
Then
// then语法 Promise.then(onFulfilled, onRejected) // 分别对应 Promise 对象的 resolve,reject 方法 // 所以为了处理error方法要改为 // .then如果参数为表达式,会返回一个新的Promise对象 loadScript('./1.js') .then(() => { // ERROR 返回的是一个新的Promise对象 loadScript('./2.js') // 返回的是执行后的 resolve return loadScript('./2.js') }, (err) => { console.log(err) }) .then(() => { loadScript('./3.js') }, (err) => { console.log(err) })
Resolve && Reject
// 返回 一个数字的resolve值 // 返回 Error事件 function test(bool) { if (bool) { return new Promise.reject(new Error('ss')) } else { return new Promise() = () => { resolve(42) } } } test(1).then(() => { console.log('ok') }, (err) => { console.log(err) })
Catch
// 更改处理错误的方法 loadScript('./1.js') .then(() => { // ERROR 返回的是一个新的Promise对象 loadScript('./2.js') // 返回的是执行后的 resolve return loadScript('./2.js') }) .then(() => { loadScript('./3.js') }) // 捕获 pending == reject 时候的方法 .catch(err =>{ console.log(err) }) // 不要用 throw方法去捕获pending的reject状态 throw new Error()
Promise.All()
// 聚合所有异步操作返回的数据 const p1 = Promise.resolve(10) const p2 = Promise.resolve(20) const p3 = Promise.resolve(30) Promise.all([p1,p2,p3]).then((values)=>{ console.log(values) })
Promise.Race()
// 并行异步操作 const p1 = () => { return new Promise = (resolve, reject) => { setTimeout(() => { console.log('1') }, 1000); } } const p2 = () => { return new Promise = (resolve, reject) => { setTimeout(() => { console.log('1') }, 500); } } // 两个异步,竞速关系 Promise.race([p1(), p2()]).then((values) => { console.log(values) })
- 推荐阅读
- Promise
Reflect 反射机制
Java的反射机制 ,在编译时不知道哪儿个类被加载,而是运行时才加载、执行
Math.floor.apply(null, [7.45]) Math.ceil.apply(null, [8.89]) let price = '123.6' if (price > 100) { Reflect.apply(Math.floor, null, [price]) } else { Reflect.apply(Math.ceil, null, [price]) } console.log(Promise.apply(price > 100 ? Math.floor : Math.ceil, null, price)) // 反射 构造函数 let d = Reflect.construct(Date, []) // d instanceof Date 判断d是否为Date的实例 console.log(d.getTime(), d instanceof Date) const student = {} // 两者的区别,在于返回值不同 // Object 返回该对象 // Reflect 返回布尔值 const r = Object.defineProperty(student, 'name', { value: 'name2' }) const r = Reflect.defineProperty(student, 'name', { value: 'name2' }) console.log(student, r) const r = Object.deleteProperty(student, 'name') const r = Reflect.deleteProperty(student, 'name') console.log(student, r) const r = Reflect.get(student, 'name') const r = Reflect.getOwnPropertyDescriptor(student, 'name') const r = Object.getOwnPropertyDescriptor(student, 'name') console.log(r) value: 1 wirtable: true enumerable: true configurable: true const d = new Date(); const r = Reflect.getPrototypeOf(d) // 查询是否含有此属性 const r = Reflect.has(student, 'name') // 禁止对象进行扩展 Reflect.preventExtensions(student) // 查看此对象是否可扩展 Reflect.isExtensible(student) // 修改对象 赋值数据 const a = ['1', '2', '3'] Reflect.set(a, 2, 'editValue') // 修改原型链对象 console.log(Reflect.getPrototypeOf(a)) Reflect.setPrototypeOf(a, Syting.property) a.sort() console.log(Reflect.getPrototypeOf(a))
Proxy 代理
强大的代理功能如何使用
// 原始信息 let o = { name: 'xiaoxiao', price: 1900, size: 120 } // Proxy基础语法 let d = Proxy(o, { // 读取数据 get(target, key) { if (key == 'price') { return target[key] + 20 } else { return target[key] } } }) // 代理的对象不允许赋值 let d = Proxy(o, { // 读取数据 get(target,key){ return target[key] }, set(target,key,value){ return false } }) //赋值操作被拦截,数据不会被修改 d.price = 300 console.log(d.price, d.name) //ES5 如何实现只读功能 //修改原型链方法 for (const [key] of Object.entries(o)) { Object.defineProperties(o,key,{ writable:false }) } o.price = 300 console.log(o.name,o.price)
Schema Vaildation
// 例子: 如果使用代理验证数据 // 验证数据 let o = { name: 'haha', price: '880' } let p = new Proxy(o, { get(target, key) { return target[key] || '' }, set:vaildator }) // 解耦 单独拿出验证方法 let vaildator = (target,key,value) =>{ if (Reflect.has(target, key)) { if (key === 'price') { if (value > 800) { return false } else { return target[key] = value } } else { return target[key] = value } } else { return false } } //随机ID class test{ constructor () { this.proxy = new Proxy({ id: Math.random().toString(36).splce(-8) },{}) } get id(){ return this.proxy.id } } let comm = new test() console.log(comm.id) let comm2 = new test() console.log(comm2.id)
Revocable Proxy
// 可撤销代理(临时代理) let d = Proxy.revocable(o, { // 读取数据 get(target, key) { return target[key] }, set(target, key, value) { return false } }) // 返回revoke 对象 console.log(d) // 撤销代理操作 d.revoke() // 阅后即焚的实现方式
Thinking
- 临时代理有哪儿场景
- 组件初始化的时候赋值一个可随机的ID
- 如何把接口数据用代理进行包装
阅读
- ES6 Proxies in Depth
Generator
Syntax 如何让遍历“停”下来
// Generator how to stop then function // ES5 loop function function loop(){ for (let i = 0 ; i<= 5; i++){ console.log(i) } } loop() // ES6 loop function // Generator 自定义遍历器 function * loop(){ for (let i = 0 ; i<= 5; i++){ yield console.log(i) } } const l = loop() l.next() l.next() l.next() // Syntax // Generator 是一个函数,比普通函数多 * 号 // yield 控制程序停下来 // next 恢复执行,next返回当前的状态 function * gen(){ let val // yie val = yield * [1,2,3] console.log(val) } const i = gen() console.log(i.next()) console.log(i.next()) // next 传参方法 console.log(i.next(10)) // Syntax 结束循环 i.return() // 抛出异常结束循环 function * gen(){ try{ yield 1 }catch (e) { console.log(e.message) } } gen.next() gen.throw(new Error('ss')) gen.next()
Scene Pratice
实现一个案例: 年终抽奖
// ES5做法 function draw (first = 1, second = 2, third = 3) { let fristPrize = ['1a', '1b', '1c', '1d', '1e', '1f', '1g', '1h'] let secondPrize = ['2a', '2b', '2c', '2d', '2e', '2f', '2g', '2h'] let thirdPrize = ['3a', '3b', '3c', '3d', '3e', '3f', '3g', '3h'] let result = [] let random for (let i = 0; i < first; i++) { random = Math.floor(Math.random() * fristPrize.lenght) result = result.concat(fristPrize.splice(random, 1)) } for (let i = 0; i < second; i++) { random = Math.floor(Math.random() * secondPrize.lenght) result = result.concat(secondPrize.splice(random, 1)) } for (let i = 0; i < third; i++) { random = Math.floor(Math.random() * thirdPrize.lenght) result = result.concat(thirdPrize.splice(random, 1)) } alert(result) return result } let t = draw() for (const value of t) { console.log(value) } //ES6 使用Generator 实现抽奖案例 function * draw (first = 1, second = 2, third = 3) { let fristPrize = ['1a', '1b', '1c', '1d', '1e', '1f', '1g', '1h'] let secondPrize = ['2a', '2b', '2c', '2d', '2e', '2f', '2g', '2h'] let thirdPrize = ['3a', '3b', '3c', '3d', '3e', '3f', '3g', '3h'] let count = 0 let random while(1){ if(count < first){ random = Math.floor(Math.random() * fristPrize.length) yield fristPrize[random] fristPrize.splice(random,1) count ++ }else if(count < first + second){ random = Math.floor(Math.random() * secondPrize.length) yield secondPrize[random] secondPrize.splice(random,1) count ++ }else if(count < first + second + third){ random = Math.floor(Math.random() * thirdPrize.length) yield thirdPrize[random] thirdPrize.splice(random,1) count ++ }else{ return false } } } let d = draw() console.log(d.next().value) console.log(d.next().value) console.log(d.next().value) console.log(d.next().value) console.log(d.next().value) console.log(d.next().value) console.log(d.next().value) // 由此可想出 es5中处理无线循环的方法 // 由此可想出 es5中处理无线循环的方法 function * count(x=1){ while(1){ if(x%3===0){ yield x } x++ } } let n = count() // 调用一次 取一次值 console.log(n.next().value) console.log(n.next().value) console.log(n.next().value)
- 推荐阅读
- 斐波那契数列
- Generators https://exploringjs.com/es6/ch_generators.html
- Thinking
- 使用Generators 实现一个斐波那契数列
Iterator 可遍历接口
如何让自定义数据结构支持可遍历
// 自定义数据结构如何支持遍历 let author = { allauthor: { indexs: ['1', '2', '3', '4'], names: ['dsa', 'jack', 'jordn', 'park'], other: ['dsass', 'asdsa', 'dsddd'] } } let r = [] // 遍历获取 value值 Object.entries for (let [, v] of Object.entries(author.allauthor)) { r = r.concat(v) } console.log(r) // ES6使用 iterator方法 手写迭代器协议 authors[Symbol.iterator] = function () { let allAuthor = this.allauthor let keys = Reflect.keys(allAuthor) let values = [] return { next(){ if(!values.length){ if(keys.length){ values = allAuthor[keys[0]] keys.shift() } return{ // done true||false 控制是否输出 done:!values.length, value:values.shift() } } } } } let r1 = [] for (const value of authors) { r.push[value] } // 可迭代协议 部署格式 使用Generator authors[Symbol.iterator] = function * (){ let allAuthor = this.allauthor let keys = Reflect.keys(allAuthor) let values = [] return { next(){ if(!values.length){ if(keys.length){ values = allAuthor[keys[0]] keys.shift() yield values.shift() }else{ return false } }else{ yield values.shift() } } } } let r2 = [] for (const value of authors) { r.push[value] }
Thinking
- 什么是自定义遍历,复杂的自定义数据结构如何使用自定义遍历?
- 什么是迭代协议,什么是可迭代协议?
- Generator 和 iterator 的关联关系?
推荐阅读
- ES6 迭代器:Iterator, Iterable 和 Generator
Modules
Export Import 模块化设计
lesson2-15-mod.js //导出变量常量 export const name = 'HELLO' export let addr = 'dsa' export let list = ['1','2','3'] //第二种方式 const name = 'HELLO' let addr = 'dsa' let list = ['1','2','3'] export{ addr, list } // 默认导出 export default name
lesson 2-15.js //导入变量常量 import (name,addr,list) from 'lesson2-15-mod' // 导入默认值 import name,(addr,list) from 'lesson2-15-mod' // 导出变量改名 import name,(addr as addr2 ,list as list2) from 'lesson2-15-mod' // 只导入默认值 可以省略括号 import name from 'lesson2-15-mod' // 只导入默认值 可以自定义导入名称 // 默认值有且最多只能有一个 // 不要讲为什么,就是这么设计的 (rush!) import name2 from 'lesson2-15-mod' console.log(name,addr)
如何导出函数
// 导出函数 export function say(content){ console.log(content) } export function run(){ console.log('runing away') } export default defaff(){ console.log('this is default function') } // 最后导出 const say = (content)=>{ console.log(content) } const run = ( )=>{ console.log('runing away') } export default say export { run }
如何导出对象
const data = { age:12, addr:'beijing' } const data2 = { age:18, addr:'shanghai' } // 对象的导出只能用default方式 export default{ data, data2 } // 导入 import obj from 'lesson2-15-mod' // 解构赋值 let {date ,data2} = obj console.log(data,data2)
如何导出一个类
class Test{ constructor(){ this.id = 2 } } export{ Test } // 默认导出 export default Test import Test form 'lesson2-15-mod' // 不带类名使用default导出导入 export default class { constructor(){ this.id = 2 } } import { Test } form 'lesson2-15-mod' // 把所有导出对象使用Mod来引用 import * as Mod form 'lesson2-15-mod' let Test = new Mod.Test() console.log(Test.id)
- 推荐阅读
- Modules
ES7 _includes _pow
includes 数组中如何判断元素是否存在
// arr数组是否包含40 arr.includes('40')
Math.pow
// 乘方 console.log( Math.pow(2,5)) // 简写乘方 console.log( 2 ** 5 )
ES8 _promise _object _string
Async
有没有比promise更优雅的方法
//ES6 如何使用异步方法 //实例化一个promise对象 //通过实例 .then方法调用 //ES8 增加async关键字 async function firstAsync(){ //可以理解为 renturn Promise.resolve(27) return 27 } // 返回一个Promise对象 console.log(firstAsync()) // 验证是否为promise对象 console.log(firstAsync() instanceof Promise) firstAsync().then(val=>{ console.log(val) })
- Thinking:
- Async 与普通function有什么区别
Await
如何保证以下的异步函数是按顺序执行的
async function firstAsync(){ let promise = new Promise((resolve,reject)=>{ setTimeout(() => { resolve('now is none') }, 1000); }) promise.then(val=>{ console.log(val); }) console.log('2'); return Promise.resolve('3') } firstAsync().then(val=>{ console.log(val); })
async function firstAsync(){ let promise = new Promise((resolve,reject)=>{ setTimeout(() => { resolve('now is none') }, 1000); }) // promise.then(val=>{ // console.log(val); // }) // await的返回值 就是promise的返回值 let result = await promise console.log(result); //相当于await Promise.resolve(30) //await 必须配合async使用,外层必须是async函数 console.log(await 30); console.log('2'); return Promise.resolve('3') } firstAsync().then(val=>{ console.log(val); })
Async Await 就是Promise的语法糖,本质上还是promise的工作原理
Object
//ES8 对keys的遍历
let grade = { "lilei":66, "han meimei":99 } let result = [] for (const k in grade) { result.push[k] } console.log(result) console.log(Object.keys(grade))
//es8 对keys, values筛选条件
let grade = { "lilei":66, "han meimei":99 } let result = [] for (const k in grade) { if( k === 'lilei'){ result.push[k] } } console.log(result) console.log(Object.keys(grade).filter(item=>item === 'lilei')) console.log(Object.values(grade).filter(item=>item > 66))
把对象变成可遍历对象 Object.entries
for (const [k,v] of Object.entries(grade)) { console.log(k,v); }
Object 获取数据的描述符
const data = { "dsadsa":"55/44", "dsdsa":"66/44", "ddsaa":"77/44", } Object.defineProperties(data,'dsdsa',{ enumerable:false, writable:false }) console.log(Object.keys(data)); //利用描述符拿到数据的所有信息 console.log(Object.getOwnPropertyDescriptors(data)); //拿到某一项数据的所有描述信息 console.log(Object.getOwnPropertyDescriptor(data,'dsdsa'));
String.补白
padStart padEnd 对string补白的方式
//es5 原始写法 for(let i =1 ;i<=31 ; i++){ if(i<10){ console.log(`0${i}`); }else{ console.log(i); } } //5位补0 for(let i =1 ;i<=31 ; i++){ console.log(i.toString().padStart(5,'0')); } for(let i =1 ;i<=310203 ; i+= 1000){ console.log(i.toString().padStart(6,'*#')); } for(let i =1 ;i<=310203 ; i+= 1000){ console.log(i.toString().padEnd(6,'*#')); }
ES9 新增内容
ES10 新增内容
来源:https://www.cnblogs.com/maozhe/p/12237879.html