【JS】ES6

ES6

杨杨杨杨杨杨杨振发布于 今天 09:58

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

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

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

1

-1

3

indexOf 无法检查出NaN

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' }

javascript

阅读 35发布于 今天 09:58

本作品系原创,采用《署名-非商业性使用-禁止演绎 4.0 国际》许可协议

avatar

杨杨杨杨杨杨杨振

1 声望

0 粉丝

0 条评论

得票时间

avatar

杨杨杨杨杨杨杨振

1 声望

0 粉丝

宣传栏

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

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

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

1

-1

3

indexOf 无法检查出NaN

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' }

以上是 【JS】ES6 的全部内容, 来源链接: www.h5w3.com/113498.html

度小满广告!风险提示:广告信息均来自平台方,不代表平台安全性,不构成建议!
度小满
回到顶部