ECMAScript新特性

ECMAScript通常被看作是javascript的标准化规范,实际上JavaScript是ECMAScript的扩展语言,ECMAScript只是提供了最基本的语法。在浏览器端的Javascript就等于ECMAScript加上web所提供的API,也就是我们常说的BOM和DOM;在Node.js中的JavaScript就等于ECMAScript加上Node所提供的一系列的API,例如fs、net、etc等API。JavaScript语言本身指的就是ECMAScript。

let和块级作用域

作用域

作用域:某个成员能够起作用的范围

作用域分为全局作用域、函数作用域、块级作用域

let

let 声明的成员只会在所声明的块中生效

for (var i = 0; i < 3; i++) {
    for (var i = 0; i < 3; i++) {
        console.log(i)
    }
    console.log('内层结束 i = ' + i)
}

//输出
1
2
3

内层结束i=3

for (var i = 0; i < 3; i++) {
    for (let i = 0; i < 3; i++) {
        console.log(i)
    }
    console.log('内层结束 i = ' + i)
}

//输出
0
1
2
内层结束i=0
0
1
2
内层结束i=1
0
1
2
内层结束i=2
复制代码

let 应用场景:循环绑定事件,事件处理函数中获取正确索引

let 修复了变量声明提升现象

数组的解构

数组的解构是根据位置去解构

const arr = [100, 200, 300]
const [foo, bar, baz] = arr
console.log(foo, bar, baz)
//输出
100 200 300

const [, , baz] = arr
console.log(baz)
//输出
300

const [foo, ...rest] = arr
console.log(rest)
//输出
[2000,300]

const [foo, bar, baz, more] = arr
console.log(more)
//输出
undefined

const [foo, bar, baz, more = 'aaa'] = arr
console.log(more)
//输出
aaa
复制代码

对象的解构

对象的解构是根据属性名去匹配提取

const obj = { name: 'zce', age: 18 }
const { name } = obj
console.log(name)
//输出
zce

const name = 'tom'
const { name: objName = 'jack' } = obj
console.log(objName)
//输出
jack
复制代码

字符串的扩展方法

const message = 'Error: foo is not defined.'
console.log(message.startsWith('Error'))//输出:true    开头是否包含某个字符串
console.log(message.endsWith('.'))//输出:true    结尾是否包含某个字符串
console.log(message.includes('foo'))//输出:true    是否包含某个字符串
复制代码

参数默认值

// 默认参数一定是在形参列表的最后
function foo (enable = true) {
    console.log('foo invoked - enable: ')
    console.log(enable)
}
foo(false)

//输出
foo invoked - enable: 
false
复制代码

剩余参数

function foo (first, ...args) {
    console.log(args)
}
foo(1, 2, 3, 4)

//输出
[2,3,4]
复制代码

箭头函数

// 最简方式
const inc = n => n + 1


// 完整参数列表,函数体多条语句,返回值仍需 return
const inc = (n, m) => {
    console.log('inc invoked')
    return n + 1
}
console.log(inc(100))
//输出
inc invokedt
101

//箭头函数不会改变this指向,在箭头函数外面拿到的this是什么,在箭头函数里面拿到的this就是什么
const person = {
    name: 'Tom',
    sayHi: function () {
        console.log(`hi, my name is ${this.name}`)
    },
    sayHi1: () => {
        console.log(`hi, my name is ${this.name}`)
    },
}
person.sayHi()
person.sayHi1()
//输出
hi, my name is Tom
hi, my name is undefined
复制代码

对象的扩展方法

Object.assign(obj1,obj2,…)用后面对象中的属性去覆盖第一个对象中的属性

Object.is()判断两个值是否为同一个值【不常用】

Proxy

Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义

const person = {
    name: 'zce',
    age: 20
}
const personProxy = new Proxy(person, {
    // 监视属性读取
    get (target, property) {
        // 若属性存在就返回值,否则返回default
        return property in target ? target[property] : 'default'
    },
    // 监视属性设置
    set (target, property, value) {
        target[property] = value
        console.log(target, property, value)
    }
})
personProxy.gender = true
console.log(personProxy.name)
console.log(personProxy.xxx)

//输出
{name:'zce',age:20} gender true
zce
default
复制代码

Class

//基本用法
class Person {
    constructor (name) {
        this.name = name
    }
    say () {
        console.log(`hi, my name is ${this.name}`)
    }
    //静态方法
    static create(name){
        return new Person('Lily')
    }
}
const p = new Person('Tom')
p.say()

//输出
hi, my name is Tom
复制代码

类的继承

class Person {
    constructor (name) {
        this.name = name
    }
    say () {
        console.log(`hi, my name is ${this.name}`)
    }
}
class Student extends Person {
    constructor (name, number) {
        super(name) // 父类构造函数
        this.number = number
    }
    hello () {
        super.say() // 调用父类成员
        console.log(`my school number is ${this.number}`)
    }
}
const s = new Student('Jack', '100')
s.hello()

//输出
hi, my name is Jack
my school number is 100
复制代码

Set

Set可以看作一个集合,里面的对象不允许重复,会返回集合对象本身,可以链式调用

const s = new Set()
s.add(1).add(2).add(3).add(4).add(2)
复制代码

size属性:获取整个集合的长度

has方法:判断集合中是否包含某个指定的值

delete方法:删除集合中某个特定的值

clear方法:清除集合中全部内容

// 应用场景:数组去重
const arr = [1, 2, 1, 3, 4, 1]
const result = [...new Set(arr)]
console.log(result)
//输出
[1,2,3,4]
复制代码

Map

Map对象保存键值对,并且能够记住键的原始插入顺序。任何值(对象或者原始值) 都可以作为一个键或一个值。

const m = new Map()
const tom = { name: 'tom' }
//存数据
m.set(tom, 90)
console.log(m)
//取数据
console.log(m.get(tom))
m.forEach((value, key) => {
    console.log(value, key)
})

//输出
Map {{name:'tom'} => 90}
90
90 {name:'tom'}
复制代码

has方法:判断集合中是否包含某个指定的值

delete方法:删除集合中某个特定的值

clear方法:清除集合中全部内容

Symbol

每个从Symbol()返回的symbol值都是唯一的

最主要的作用是为对象添加独一无二的属性名

直接使用Symbol()创建新的symbol类型,并用一个可选的字符串作为其描述

console.log(Symbol('foo'))
复制代码

两个 Symbol 永远不会相等

console.log(Symbol('foo')===Symbol('foo'))//false

// Symbol 全局注册表 
//for方法可以实现全局复用同一个Symbol,接收一个字符串作为参数,相同的字符串会返回相同的Symbol值
const s1 = Symbol.for('foo')
const s2 = Symbol.for('foo')
console.log(s1 === s2)//true
//for方法维护的是字符串和Symbol的对应关系,如果传入的不是字符串,会转成字符串
console.log(  Symbol.for(true) === Symbol.for('true'))//true

// Symbol 属性名获取
const obj = {  [Symbol()]: 'symbol value',  foo: 'normal value'}
console.log(Object.getOwnPropertySymbols(obj))
复制代码

for···of遍历

// for...of 只能遍历数组结构的数据类型,循环取到的是每个元素,而不是对应的下标
const arr = [100, 200, 300, 400]
for (const item of arr) {
    console.log(item)
}
//输出
100
200
300
400


// for...of 循环可以替代 数组对象的 forEach 方法
arr.forEach(item => { console.log(item) })
for (const item of arr) {
    console.log(item)
    if (item > 100) {
        //for...of可以使用break随时终止遍历
        break
    }
}
// forEach 无法跳出循环,必须使用 some 或者 every 方法
// arr.forEach() // 不能跳出循环
arr.some()//返回true会终止遍历
arr.every()//返回false会终止遍历


// 遍历 Set 与遍历数组相同
const s = new Set(['foo', 'bar'])
for (const item of s) {
    console.log(item)
}
//输出
foo
bar


// 遍历 Map 可以配合数组结构语法,直接获取键值
const m = new Map()
m.set('foo', '123')
m.set('bar', '345')
for (const [key, value] of m) {
    console.log(key, value)
}
//输出
['foo','123']
['bar','345']


// 普通对象不能被直接 for...of 遍历
const obj = { foo: 123, bar: 456 }
for (const item of obj) {
    console.log(item)
}
//输出
TypeErroe: obj is not iterable
复制代码

for … of循环和for … in循环有何区别?

for … in循环遍历的实际上是对象的属性名称。一个Array数组实际上也是一个对象,它的每个元素的索引被视为一个属性。

var a = ['A', 'B', 'C']; a.name = 'Hello';
for (var x in a) {
    console.log(x); // '0', '1', '2', 'name'
}
复制代码

for … in循环将把name包括在内,但Array的length属性却不包括在内。

for … of循环只循环集合本身的元素:

var a = ['A', 'B', 'C'];
a.name = 'Hello';
for (var x of a) {
    console.log(x); // 'A', 'B', 'C'
}
复制代码

Iterator

实现Iterable接口是for…of的前提,其内部维护了一个指针,调用next方法可以实现内部的遍历

// 迭代器(Iterator)
const set = new Set(['foo', 'bar', 'baz'])
const iterator = set[Symbol.iterator]()
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())

//输出
{value:'foo',done:fale}
{value:'bar',done:fale}
{value:'baz',done:fale}
{value:undefined,done:true}
{value:undefined,done:true}

//优化
while (true) {
    const current = iterator.next()
    if (current.done) {
        break // 迭代已经结束了,没必要继续了
    }
    console.log(current.value)
}

//输出
{value:'foo',done:fale}
{value:'bar',done:fale}
{value:'baz',done:fale}

// 实现可迭代接口(Iterable)
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)
}

//输出
foo
bar
baz


// 使用 Generator 函数实现 iterator 方法
const todos = {
    store: ['foo', 'bar', 'baz'],
    [Symbol.iterator]: function * () {
        for (const item of store) {
            yield item
        }
    }
}

for (const item of todos) {
    console.log(item)
}
//输出
foo
bar
baz
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享