共计 16858 个字符,预计需要花费 43 分钟才能阅读完成。
let 与块级作用域
JS 中作用域有:全局作用域、函数作用域。没有块作用域的概念。ECMAScript 6(简称 ES6)中新增了块级作用域。
块作用域由 {} 包含,if 语句和 for 语句外面的 {} 也属于块作用域。
var elements = [{}, {}, {}]; | |
for (var i=0; i < elements.length; i++) {elements[i].onclick = function() {console.log(i); | |
} | |
} | |
elements[1].onclick(); | |
//// | |
PS F:\ 拉钩前端 \lagou> node .\task1\task1.js | |
3 | |
3 | |
3 |
通过闭包
var elements = [{}, {}, {}]; | |
for (var i = 0; i < elements.length; i++) {elements[i].onclick = (function (i) {return function () {console.log(i); | |
} | |
})(i) | |
} | |
elements[0].onclick(); | |
elements[1].onclick(); | |
elements[2].onclick(); | |
//// | |
PS F:\ 拉钩前端 \lagou> node .\task1\task1.js | |
0 | |
1 | |
2 |
应用 let
var elements = [{}, {}, {}]; | |
for (let i = 0; i < elements.length; i++) {elements[i].onclick = function () {console.log(i); | |
} | |
} | |
elements[0].onclick(); | |
elements[1].onclick(); | |
elements[2].onclick(); | |
//// | |
PS F:\ 拉钩前端 \lagou> node .\task1\task1.js | |
0 | |
1 | |
2 |
数组的解构
const arr = [100,200,300]; | |
const [a,b,c] = arr; | |
console.log(a,b,c); | |
//// | |
PS F:\ 拉钩前端 \lagou> node .\task1\task1.js | |
100 200 300 |
只定义一个变量 须要 把其它地位空进去
const arr = [100,200,300]; | |
const [,,c] = arr; | |
console.log(c); | |
//// | |
PS F:\ 拉钩前端 \lagou> node .\task1\task1.js | |
300 |
应用 … 定义剩下的变量
只能定义在最初的地位
const arr = [100,200,300]; | |
const [a, ...rest] = arr; | |
console.log(rest); | |
//// | |
PS F:\ 拉钩前端 \lagou> node .\task1\task1.js | |
[200, 300] |
const arr = [100,200,300]; | |
const [...rest] = arr; | |
console.log(rest); | |
//// | |
PS F:\ 拉钩前端 \lagou> node .\task1\task1.js | |
[100, 200, 300] |
const arr = [100,200,300]; | |
const [...rest,c] = arr; | |
console.log(rest); | |
//// | |
F:\ 拉钩前端 \lagou\task1\task1.js:15 | |
const [...rest,c] = arr; | |
^^^^^^^ |
解构的时候赋初始值
const arr = [100, 200, 300]; | |
const [a, b, c = 123, d = 'defaultValue'] = arr; | |
console.log(c, d); | |
//// | |
PS F:\ 拉钩前端 \lagou> node .\task1\task1.js | |
300 defaultValue |
解构实例:解析门路
// 传统写法 | |
const path = '/foo/bar/baz'; | |
const temp = path.split('/'); | |
const rootdir = temp[1]; | |
console.log(temp); | |
console.log(rootdir); | |
//// | |
PS F:\ 拉钩前端 \lagou> node .\task1\task1.js | |
['','foo','bar','baz'] | |
foo |
// 解构写法 | |
const path = '/foo/bar/baz'; | |
const [,rootdir] = path.split('/'); | |
console.log(rootdir); | |
//// | |
PS F:\ 拉钩前端 \lagou> node .\task1\task1.js | |
foo |
对象的解构
对象是通过 key,数组是通过下标
const obj = {name:'yangzhen' , age:24}; | |
const {name , age , sex} = obj; | |
console.log(sex,name,age); | |
//// | |
PS F:\ 拉钩前端 \lagou> node .\task1\task1.js | |
undefined yangzhen 24 |
不应用别名
const obj = {name:'yangzhen' , age:24}; | |
const name = 'jack'; | |
const {name , age , sex} = obj; | |
console.log(sex,name,age); | |
//// | |
const {name , age , sex} = obj; | |
^ | |
SyntaxError: Identifier 'name' has already been declared |
应用别名 赋初始值
const obj = {name:'yangzhen' , age:24}; | |
const name = 'jack'; | |
const {name:myname , age , sex = 18} = obj; | |
console.log(sex,myname,age); | |
//// | |
PS F:\ 拉钩前端 \lagou> node .\task1\task1.js | |
18 yangzhen 24 |
字符串的扩大办法
const {log} = console | |
const message = 'Error: foo is noe defined.' | |
log (message.startsWith('Error'), | |
message.endsWith('.'), | |
message.includes('is') | |
) | |
//// | |
true true true |
函数参数的默认值
原始办法(对于布尔类型)
// 函数参数的默认值 | |
function foo(enable) {// 原始办法(对于布尔类型) | |
enable = enable === undefined ? true : false | |
console.log(enable) | |
} | |
foo() //// true | |
foo(false) //// false |
原始办法(对于其它类型)
// 函数参数的默认值 | |
function foo(enable) { | |
// 原始办法 | |
enable = enable || 0 | |
console.log(enable) | |
} | |
foo() //// 0 | |
foo(5) //// 5 |
ES6 语法
function foo(enable = true){console.log(enable) | |
} | |
foo() //// true | |
foo(false) //// false |
残余参数
形式一:应用 arguments
function foo(){console.log(arguments) | |
} | |
foo(1,2,3,4) | |
//// | |
PS E:\lagou 前端 \demo> node .\part1\test1.js | |
[Arguments] {'0': 1, '1': 2, '2': 3, '3': 4} |
function foo(){const [a,b,c,d] = arguments | |
console.log(a,b,c,d) | |
} | |
foo('a',2,3,4) | |
//// | |
PS E:\lagou 前端 \demo> node .\part1\test1.js | |
a 2 3 4 |
形式二:应用 …
…args 放在最初 只能应用一次
function foo(first,...args){console.log(first) | |
console.log(args) | |
} | |
foo('a',2,3,4) | |
//// | |
PS E:\lagou 前端 \demo> node .\part1\test1.js | |
a | |
[2, 3, 4] |
···开展数组
const arr = [1,2,3,4] | |
console.log(...arr) | |
//// | |
PS E:\lagou 前端 \demo> node .\part1\test1.js | |
1 2 3 4 |
箭头函数与 this
一般函数:this 的指向在函数创立的时候是决定不了的,在调用的时候能力决定,谁调用的就指向谁,肯定要搞清楚这个。
箭头函数没有 prototype(原型),所以箭头函数自身没有 this。箭头函数外部的 this 是词法作用域,由上下文确定,this 指向在定义的时候继承自外层第一个一般函数的 this。函数体内的 this 对象,就是定义时所在的对象,与应用时所在的对象无关。
const name = 'jack' | |
const person = { | |
name: 'tom', | |
sayHi: function(){console.log(`my name is ${this.name}`) | |
} | |
} | |
person.sayHi() | |
//// | |
PS E:\lagou 前端 \demo> node .\part1\test1.js | |
my name is tom |
const name = 'jack' | |
const person = { | |
name: 'tom', | |
sayHi: function(){console.log(`my name is ${name}`) | |
} | |
} | |
person.sayHi() | |
//// | |
PS E:\lagou 前端 \demo> node .\part1\test1.js | |
my name is jack |
应用箭头函数
箭头函数不会扭转 this 的指向
const name = 'jack' //// 这个 name 并不是 this.name | |
const person = { | |
name: 'tom', | |
sayHi: () => {console.log(`my name is ${this.name}`) | |
} | |
} | |
person.sayHi() | |
//// | |
PS E:\lagou 前端 \demo> node .\part1\test1.js | |
my name is undefined |
const name = 'jack' | |
const person = { | |
name: 'tom', | |
sayHi: () => {console.log(`my name is ${name}`) | |
} | |
} | |
console.log(this) | |
console.log(this.name) | |
person.sayHi() | |
//// | |
PS E:\lagou 前端 \demo> node .\part1\test1.js | |
{} | |
undefined | |
my name is jack |
传统形式_this 的应用
const person = { | |
name: 'tom', | |
sayHi: function() {console.log(`my name is ${this.name}`) | |
}, | |
sayHiAsync:function(){setTimeout(function () {console.log(`my name is ${this.name}`) | |
}, 1000); | |
} | |
} | |
person.sayHi() | |
person.sayHiAsync() | |
//// | |
PS E:\lagou 前端 \demo> node .\part1\test1.js | |
my name is tom | |
my name is undefined |
const person = { | |
name: 'tom', | |
sayHi: function() {console.log(`my name is ${this.name}`) | |
}, | |
sayHiAsync:function(){ | |
_this = this; | |
setTimeout(function () {console.log(`my name is ${_this.name}`) | |
}, 1000); | |
} | |
} | |
person.sayHi() | |
person.sayHiAsync() | |
//// | |
PS E:\lagou 前端 \demo> node .\part1\test1.js | |
my name is tom | |
my name is tom |
setTimeout 应用箭头函数 能够防止_this
箭头函数外部的 this 是词法作用域,由上下文确定
const person = { | |
name: 'tom', | |
sayHi: () => {console.log(`my name is ${this.name}`) | |
}, | |
sayHiAsync:function(){setTimeout(()=> {console.log(`my name is ${this.name}`) | |
}, 1000); | |
} | |
} | |
person.sayHi() | |
person.sayHiAsync() | |
//// | |
PS E:\lagou 前端 \demo> node .\part1\test1.js | |
my name is undefined | |
my name is tom |
对象字面量加强
const bar = '345' | |
const obj = { | |
foo: 123, | |
//bar:bar | |
bar, | |
//method1:function(){// console.log(this) | |
//} | |
method1(){console.log(this) | |
}, | |
[Math.random()]:456 // 能够间接减少 | |
} | |
// 在传统办法中,对象动静的减少属性 | |
obj[Math.random()] = 123 | |
console.log(obj) | |
obj.method1() | |
//// | |
PS E:\lagou 前端 \demo> node .\part1\test1.js | |
{ | |
foo: 123, | |
bar: '345', | |
method1: [Function: method1], | |
'0.8616180359346404': 123 | |
} | |
{ | |
foo: 123, | |
bar: '345', | |
method1: [Function: method1], | |
'0.8616180359346404': 123 | |
} |
对象扩大办法
Object.assign 将多个源对象中的属性复制到指标对象
const source1 = { | |
a:123, | |
b:123 | |
} | |
const source2 = { | |
b:789, | |
d:789 | |
} | |
const target = { | |
a:456, | |
c:456 | |
} | |
const result = Object.assign(target,source1,source2) | |
console.log(target) | |
console.log(result === target) | |
//// | |
PS E:\lagou 前端 \demo> node .\part1\test1.js | |
{a: 123, c: 456, b: 789, d: 789} | |
true |
案例
function func(obj){ | |
obj.name = 'func obj' | |
console.log(obj) | |
} | |
const obj = {name: 'global obj'} | |
func(obj) | |
console.log(obj) | |
//// | |
{name: 'func obj'} | |
{name: 'func obj'} |
function func(obj){const funObj = Object.assign({},obj) | |
funObj.name = 'func obj' | |
console.log(funObj) | |
} | |
const obj = {name: 'global obj'} | |
func(obj) | |
console.log(obj) | |
//// | |
{name: 'func obj'} | |
{name: 'global obj'} |
Proxy 代理对象
const person = { | |
name: 'yang', | |
age: 18 | |
} | |
// 参数 1: 代理对象 | |
// 参数 2: 代理的解决对象 | |
const personProxy = new Proxy(person,{ | |
// 通过 get 办法去监督属性拜访 | |
// 参数 1: 所代理的指标对象 | |
// 参数 2: 内部所拜访的属性名 | |
get(target,property){console.log(target,property) | |
return 100 | |
}, | |
// 通过 set 办法去实现属性设置 | |
set(){} | |
}) | |
console.log(personProxy.name) | |
//// | |
PS E:\lagou 前端 \demo> node .\part1\test1.js | |
{name: 'yang', age: 18} name | |
100 |
const person = { | |
name: 'yang', | |
age: 18 | |
} | |
// 参数 1: 代理对象 | |
// 参数 2: 代理的解决对象 | |
const personProxy = new Proxy(person,{ | |
// 通过 get 办法去监督属性拜访 | |
// 参数 1: 所代理的指标对象 | |
// 参数 2: 内部所拜访的属性名 | |
get(target,property){return property in target ? target[property] : 'default' | |
}, | |
// 通过 set 办法去实现属性设置 | |
set(){} | |
}) | |
console.log(personProxy.name) | |
console.log(personProxy.xxxx) | |
//// | |
PS E:\lagou 前端 \demo> node .\part1\test1.js | |
yang | |
default |
const person = { | |
name: 'yang', | |
age: 18 | |
} | |
// 参数 1: 代理对象 | |
// 参数 2: 代理的解决对象 | |
const personProxy = new Proxy(person,{ | |
// 通过 get 办法去监督属性拜访 | |
// 参数 1: 所代理的指标对象 | |
// 参数 2: 内部所拜访的属性名 | |
get(target,property){return property in target ? target[property] : 'default' | |
}, | |
// 通过 set 办法去实现属性设置 | |
//1. 所代理的指标对象 | |
//2. 要写入的属性名 | |
//3. 要写入的值 | |
set(target,property,value){if(property === 'age') {if (!Number.isInteger(value)) {throw new TypeError(`${value} is not an int`) | |
} | |
} | |
target[property] = value | |
} | |
}) | |
personProxy.age = 30 | |
personProxy.sex = 'man' | |
console.log(personProxy) | |
//// | |
PS E:\lagou 前端 \demo> node .\part1\test1.js | |
{name: 'yang', age: 30, sex: 'man'} |
proxy 和 Object.defineProperty()
Object.defineProperty()只能监听对象的读写
proxy 还能够有更多的操作
const person = { | |
name: 'yang', | |
age: 18 | |
} | |
const personProxy = new Proxy(person,{deleteProperty(target,property){console.log('delete',property) | |
delete target[property] | |
} | |
}) | |
delete personProxy.age | |
console.log(person) | |
//// | |
PS E:\lagou 前端 \demo> node .\part1\test1.js | |
delete age | |
{name: 'yang'} |
proxy 更好的反对数组对象的监督
const list = [] | |
const listProxy = new Proxy(list,{set(target,property,value) {console.log('set',property,value) | |
target[property] = value | |
return true // 示意设置胜利, 不写会报错 | |
} | |
}) | |
listProxy.push(100) | |
listProxy.push(200) | |
console.log('list',list) | |
//// | |
PS E:\lagou 前端 \demo> node .\part1\test1.js | |
set 0 100 | |
set length 1 | |
set 1 200 | |
set length 2 | |
list [100, 200] |
Reflect 对立的对象操作 API
动态类,封装了一系列对对象的底层操作
Reflet 成员办法就是Proxy 解决对象的默认实现
去掉 Reflect
const person = { | |
name: 'yang', | |
age: 18 | |
} | |
const personProxy = new Proxy(person,{get(target,property) {console.log('watch logic') | |
// return Reflect.get(target,property) | |
} | |
}) | |
console.log(personProxy.age) | |
//// | |
PS E:\lagou 前端 \demo> node .\part1\test1.js | |
watch logic | |
undefined |
增加 Reflect
const person = { | |
name: 'yang', | |
age: 18 | |
} | |
const personProxy = new Proxy(person,{get(target,property) {console.log('watch logic') | |
return Reflect.get(target,property) | |
} | |
}) | |
console.log(personProxy.age) | |
//// | |
PS E:\lagou 前端 \demo> node .\part1\test1.js | |
watch logic | |
18 |
Reflect 的作用:对立的提供一套用于操作对象的 API
不应用 Reflect 对对象的操作
const person = { | |
name: 'yang', | |
age: 18 | |
} | |
// 判断 对象是否有 属性 | |
console.log('name' in person) | |
// 获取对象所有的 Key | |
console.log(Object.keys(person)) | |
// 删除对象的属性 | |
console.log(delete person['age']) | |
console.log(person) | |
//// | |
PS E:\lagou 前端 \demo> node .\part1\test1.js | |
true | |
['name', 'age'] | |
true | |
{name: 'yang'} |
应用 Reflect 对对象的操作
const person = { | |
name: 'yang', | |
age: 18 | |
} | |
// 判断 对象是否有 属性 | |
console.log(Reflect.has(person,'name')) | |
// 获取对象所有的 Key | |
console.log(Reflect.ownKeys(person)) | |
// 删除对象的属性 | |
console.log(Reflect.deleteProperty(person,'age')) | |
console.log(person) | |
//// | |
PS E:\lagou 前端 \demo> node .\part1\test1.js | |
true | |
['name', 'age'] | |
true | |
{name: 'yang'} |
Promise 一种更优的异步编程解决方案
解决了传统异步编程中函数嵌套过深的问题
class 关键字
传统应用 prototype
function Person (name) {this.name = name;} | |
Person.prototype.say = function () {console.log(`my name is ${this.name}`) | |
} | |
const p = new Person('tom') | |
p.say() | |
//// | |
PS E:\lagou 前端 \demo> node .\part1\test1.js | |
my name is tom |
应用 class
class Person {constructor(name) {this.name = name} | |
say() {console.log(`my name is ${this.name}`) | |
} | |
} | |
const p = new Person('tom') | |
p.say() | |
//// | |
PS E:\lagou 前端 \demo> node .\part1\test1.js | |
my name is tom |
静态方法
class Person {constructor(name) {this.name = name} | |
say() {console.log(`my name is ${this.name}`) | |
} | |
static create(name) {return new Person(name) | |
} | |
} | |
const p = Person.create('tom') | |
p.say() | |
//// | |
PS E:\lagou 前端 \demo> node .\part1\test1.js | |
my name is tom |
继承
class Person {constructor(name) {this.name = name} | |
say() {console.log(`my name is ${this.name}`) | |
} | |
static create(name) {return new Person(name) | |
} | |
} | |
class Student extends Person {constructor(name,number) {super(name) | |
this.number = number | |
} | |
hello() {super.say() | |
console.log(`my number is ${this.number}`) | |
} | |
} | |
const s = new Student('jack',100) | |
s.hello() | |
//// | |
PS E:\lagou 前端 \demo> node .\part1\test1.js | |
my name is jack | |
my number is 100 |
Set 数据类型
const s = new Set() | |
//add 返回的是 Set 所以能够链式调用 | |
s.add(1).add(2).add(3).add(4).add(4).add(5) | |
//set 元素 没有反复 所以 主动去重 | |
console.log(s) //// Set {1, 2, 3, 4, 5} | |
//Set 的遍历 | |
s.forEach(i => {console.log(i) //// 1 2 3 4 5 | |
}) | |
//Set 的罕用办法 | |
console.log(s.size) //// 5 | |
console.log(s.has(100)) ////false | |
console.log(s.delete(3)) ////true | |
console.log(s) //// Set {1, 2, 4, 5} |
Set 对 数组的去重解决
Array.from() 能够将 Set 转化为 Array
const arr = [1,2,3,1,2,1,4,1] | |
//const result = Array.from(new Set(arr)) | |
const result = [...new Set(arr)] | |
console.log(result) | |
PS E:\lagou 前端 \demo> node .\part1\test1.js | |
[1, 2, 3, 4] |
Map 数据结构
一般键值对
对象的 key 只能是 String 类型,不是 String 类型会被主动转化为 String
const obj = {} | |
obj[true] = 'value' | |
obj[123] = 'value' | |
obj[{a: 1}] = 'value' | |
console.log(Object.keys(obj)) | |
//// | |
PS E:\lagou 前端 \demo> node .\part1\test1.js | |
['123', 'true', '[object Object]' ] |
Map 类型
const m = new Map() | |
const tom = {name:'tom'} | |
m.set(tom,90) | |
console.log(m) | |
console.log(m.get(tom)) | |
//Map 的遍历 | |
m.forEach((value,key)=>{console.log(value,key) | |
}) | |
//// | |
PS E:\lagou 前端 \demo> node .\part1\test1.js | |
Map {{ name: 'tom'} => 90 } | |
90 | |
90 {name: 'tom'} |
Symbol 新的数据类型
最次要的作用就是为对象增加 举世无双 的属性名
const s = Symbol() | |
console.log(s) | |
console.log(typeof s) | |
console.log(Symbol() === Symbol()) | |
// 增加形容文本 | |
// 留神:即便增加同一形容文本 Symbol 也是不一样的 | |
console.log(Symbol('foo')) | |
//// | |
PS F:\ 拉钩前端 \lagou> node .\task1\task1.js | |
Symbol() | |
symbol | |
false | |
Symbol(foo) |
设置对象公有成员
const name = Symbol(); | |
const person = {[name]:'yang', | |
say(){console.log(this[name]) | |
} | |
} | |
console.log(person[Symbol()]) | |
person.say() | |
//// | |
PS F:\ 拉钩前端 \lagou> node .\task1\task1.js | |
undefined | |
yang |
for of 循环
是一种数据对立的遍历形式
const arr = [100,200,300,400,500] | |
for (item of arr) {console.log(item) ////100 200 300 400 | |
if(item > 300){break} | |
} | |
// 不能跳出循环 | |
arr.forEach(item =>{console.log(item) ////100 200 300 400 | |
}) | |
//some() 办法用于检测数组中的元素是否满足指定条件(函数提供)。//some() 办法会顺次执行数组的每个元素:// 如果有一个元素满足条件,则表达式返回 true , 残余的元素不会再执行检测。// 如果没有满足条件的元素,则返回 false。//every() 办法用于检测数组所有元素是否都合乎指定条件(通过函数提供)。//every() 办法应用指定函数检测数组中的所有元素:// 如果数组中检测到有一个元素不满足,则整个表达式返回 false,且残余的元素不会再进行检测。// 如果所有元素都满足条件,则返回 true。const result = arr.some((item)=>{return item > 300}) | |
console.log(result) ////true | |
for (i in arr) {console.log(arr[i]) ////100 200 300 400 500 | |
} |
Set 的 for of 遍历
const s = new Set(['foo','bar']) | |
for (const item of s) {console.log(item) | |
} | |
//// | |
PS F:\ 拉钩前端 \lagou> node .\task1\task1.js | |
foo | |
bar |
Map 的 for of 遍历
const m = new Map() | |
m.set('foo','123') | |
m.set('bar','456') | |
for(const item of m) {console.log(item) | |
} | |
//// | |
PS F:\ 拉钩前端 \lagou> node .\task1\task1.js | |
['foo', '123'] | |
['bar', '456'] |
应用数组的解构失去 K V
const m = new Map() | |
m.set('foo','123') | |
m.set('bar','456') | |
for(const [key,value] of m ) {console.log(key,value) | |
} | |
//// | |
PS F:\ 拉钩前端 \lagou> node .\task1\task1.js | |
foo 123 | |
bar 456 |
实现可迭代接口 Iterable
对象是不能够间接迭代的
在对象中挂一个 iterator 办法,在这个办法中返回一个迭代器对象
接口约定:外部必须要有一个用于迭代的 next 办法
const obj = {store: ['foo','bar','baz'], | |
[Symbol.iterator]: function() { | |
let index = 0 | |
const self = this | |
return {next: function() { | |
const result = {value:self.store[index], | |
done:index >= self.store.length | |
} | |
index++ | |
return result | |
} | |
} | |
} | |
} | |
for (const item of obj) {console.log('循环',item) | |
} | |
//// | |
PS F:\ 拉钩前端 \lagou> node .\task1\task1.js | |
循环 foo | |
循环 bar | |
循环 baz |
迭代器模式
实现迭代器的目标
场景:协同开发一个工作清单利用
//============== 我的代码 ============== | |
const todos= {life:['吃饭','睡觉','打豆豆'], | |
learn:['语言','数学','英语'], | |
} | |
//============== 你的代码 ============== | |
for(const item of todos.life){console.log(item) | |
} | |
for(const item of todos.learn){console.log(item) | |
} | |
如果我须要在我的 todos 数据列表里增加数据时,你的代码就须要作出相应的更改,对于调用来说,代码耦合度太高
//============== 我的代码 ============== | |
const todos= {life:['吃饭','睡觉','打豆豆'], | |
learn:['语言','数学','英语'], | |
work:['唱歌'] | |
} | |
//============== 你的代码 ============== | |
for(const item of todos.life){console.log(item) | |
} | |
for(const item of todos.learn){console.log(item) | |
} | |
for(const item of todos.work){console.log(item) | |
} |
如何解决:
如果我的代码可能对外对立提供一个遍历的接口
对于调用者而已,就不必去关怀它外部的数据结构,也不必放心构造的扭转
咱们能够本人写一个办法来实现:
//============== 我的代码 ============== | |
const todos = {life: ['吃饭', '睡觉', '打豆豆'], | |
learn: ['语言', '数学', '英语'], | |
work: ['唱歌'], | |
each: function (callback) {const all = [].concat(this.life, this.learn, this.work) | |
for (item of all) {callback(item) | |
} | |
} | |
} | |
//============== 你的代码 ============== | |
todos.each(function (item) {console.log(item); | |
}) |
用迭代器的办法实现
//============== 我的代码 ============== | |
const todos = {life: ['吃饭', '睡觉', '打豆豆'], | |
learn: ['语言', '数学', '英语'], | |
work: ['唱歌'], | |
[Symbol.iterator]:function() {// 应用对象开展符 等同于 [].concat | |
const all = [...this.life,...this.learn,...this.work] | |
let index = 0 | |
return{next:function(){ | |
return{value:all[index], | |
done: index++ >= all.length //true 就迭代实现了 | |
} | |
} | |
} | |
} | |
} | |
//============== 你的代码 ============== | |
for(item of todos) {console.log(item) | |
} | |
//// | |
PS F:\ 拉钩前端 \lagou> node .\task1\task1.js | |
吃饭 | |
睡觉 | |
打豆豆 | |
语言 | |
数学 | |
英语 | |
唱歌 |
迭代器的外围 就是对外提供对立遍历接口,让内部不必去放心外部的数据结构是怎么样的
这里展现的 each 办法只实用于这里展现的数组构造
而 ES2015 种的迭代器 是从语言层面去实现的迭代器模式,所以说它实用于任何数据结构,只有实现了 iterable 接口,那咱们就能够实现应用 for…of 遍历对象
生成器函数
解决异步编程回调嵌套过深所导致的问题
function * foo(){console.log('test') | |
return 100 | |
} | |
const result = foo() | |
console.log(result) | |
console.log(result.next()) | |
//// | |
Object [Generator] {} | |
test | |
{value: 100, done: true} |
惰性执行
yield
function * foo(){console.log('111') | |
yield 100 | |
console.log('222') | |
yield 200 | |
console.log('333') | |
yield 300 | |
} | |
const generator = foo() | |
console.log(generator) | |
console.log(generator.next()) | |
console.log(generator.next()) | |
console.log(generator.next()) | |
console.log(generator.next()) | |
//// | |
Object [Generator] {} | |
111 | |
{value: 100, done: false} | |
222 | |
{value: 200, done: false} | |
333 | |
{value: 300, done: false} | |
{value: undefined, done: true} |
Generator 利用
案例一:发号器
function * createIdMaker(){ | |
let id = 1 | |
while(true) {yield id++} | |
} | |
const idMaker = createIdMaker() | |
console.log(idMaker.next().value) | |
console.log(idMaker.next().value) | |
console.log(idMaker.next().value) | |
console.log(idMaker.next().value) | |
//// | |
PS E:\lagou 前端 \demo> node .\part1\test1.js | |
1 | |
2 | |
3 | |
4 |
案例二:应用 Generator 函数实现 Iterator 办法
const todos = {life: ['吃饭', '睡觉', '打豆豆'], | |
learn: ['语言', '数学', '英语'], | |
work: ['唱歌'], | |
[Symbol.iterator]: function* () {const all = [...this.life, ...this.learn, ...this.work] | |
for (item of all) {yield item} | |
} | |
} | |
for (const item of todos) {console.log(item) | |
} | |
//// | |
PS E:\lagou 前端 \demo> node .\part1\test1.js | |
吃饭 | |
睡觉 | |
打豆豆 | |
语言 | |
数学 | |
英语 | |
唱歌 |
ES2016
Array.prototype.includes
咱们先看看 indexOf 办法
const arr = ['foo',1,NaN,false] | |
console.log(arr.indexOf('foo')) | |
console.log(arr.indexOf(1)) | |
console.log(arr.indexOf(NaN)) | |
console.log(arr.indexOf(false)) | |
//// | |
PS F:\ 拉钩前端 \lagou> node .\task1\task1.js | |
0 | |
1 | |
-1 | |
3 |
indexOf 无奈查看出 NaN
NaN 是一个非凡的数字值(typeof NaN 的后果为 number),是 not a number 的缩写,示意不是一个非法的数字。
留神点:NaN 是惟一一个和本身不相等的值:NaN === NaN // false
includes 能够查看出 NaN 返回布尔值
const arr = ['foo',1,NaN,false] | |
console.log(arr.includes('foo')) | |
console.log(arr.includes(1)) | |
console.log(arr.includes(NaN)) | |
console.log(arr.includes(false)) | |
//// | |
PS F:\ 拉钩前端 \lagou> node .\task1\task1.js | |
true | |
true | |
true | |
true |
指数运算符
console.log(Math.pow(2,10)) | |
console.log(2 ** 10) | |
//// | |
PS F:\ 拉钩前端 \lagou> node .\task1\task1.js | |
1024 | |
1024 |
ES2017
Object.values
const obj = { | |
foo: 'value1', | |
bar: 'balue2' | |
} | |
console.log(Object.values(obj)) | |
//// | |
PS F:\ 拉钩前端 \lagou> node .\task1\task1.js | |
['value1', 'balue2'] |
Object.entries
数组模式返回键值对
const obj = { | |
foo: 'value1', | |
bar: 'balue2' | |
} | |
console.log(Object.entries(obj)) | |
//// | |
PS F:\ 拉钩前端 \lagou> node .\task1\task1.js | |
[[ 'foo', 'value1'], ['bar', 'balue2'] ] |
因而能够应用 for of
const obj = { | |
foo: 'value1', | |
bar: 'balue2' | |
} | |
for (const [key, value] of Object.entries(obj)) {console.log(key, value) | |
} | |
//// | |
PS F:\ 拉钩前端 \lagou> node .\task1\task1.js | |
foo value1 | |
bar balue2 |
应用 entries 转化 Map 对象
const obj = { | |
foo: 'value1', | |
bar: 'balue2' | |
} | |
console.log(new Map(Object.entries(obj))) | |
//// | |
PS F:\ 拉钩前端 \lagou> node .\task1\task1.js | |
Map {'foo' => 'value1', 'bar' => 'balue2'} |