欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

es2016新增内容

程序员文章站 2024-02-21 10:07:33
...

ECMAscript模块

在浏览器环境中,JavaScript分为两大部分,一个是ECMAScript,一个是node api:BOM和DOM

在编写代码之前需要构建一下项目,添加一下工具。
首先用到的就是package.json:在node.js中,模块是一个库或者框架,也是一个node.js项目。node.js遵循模块化的架构,当我们创建了一个node.js项目,意味着创建了一个模块,这个模块的描述文件就是package.json
nodemon: 修改代码后自动执行代码

安装nodemon: npm install -g nodemon (-g 代表全局安装,代表所有项目无论有没安装 nodemon,都可以直接在命令行上运行,因此我们不会在项目里的 node_modules 看到 nodemon。)

let与块级作用域

在ES2015之前是没有块级作用域的,写在{ }内的变量在{ }外面也能取到

var会导致变量提升问题,let就不会

模板字符串

${这里可以传入js语句} 支持换行

带标签的模板字符串

const name = 'aaa'
const age = 10
function tage(strings, name, age) {
	//可以在这里进行一些处理
    console.log(strings, name, age) //['name:','age:']  'aaa'  10
}
const result = tags`name:${name}age:${age}`

字符串的扩展方法

const MESSAGE = 'Error: foo is undefined.'
function strFun(message) {
    //判断字符串的开头是否以xx开始
    console.log(message.startsWith('Error')) //true
    //判断字符串是否以xxx结尾
    console.log(message.endsWith('.')) //true
    //判断字符串是否包含xxx
    console.log(message.includes('foo')) //true
}
strFun(MESSAGE);

剩余参数

function func(...args) {
	console.log(args) //[1,2,3]
}
func(1,2,3)

箭头函数和this

普通函数的this指向他的调用者,而箭头函数的this指向调用者的上下文环境,箭头函数本身是没有this指向的。
这里要注意的是,这个函数的执行环境是浏览器环境还是node环境。浏览器环境因为有window对象。

const person = {
    name: 'aaa',
    sayHi: () => {
        console.log(this.name) ;
    },
    sayHiAync: function () {
        setTimeout(function() {
            console.log(this.name) ;
        }, 1000)
    }
}
person.sayHi() //aaa
person.sayHiAync() //undefined

对象字面量增强

const name = 'abc';
let obj = {
    method1() {
        console.log(111)
    },
    [name]: 'myName'
}
console.log(obj.method1()) //111
console.log(obj.abc) //myName

对象扩展方法

Object.assign(): 将多个源对象中的属性复制到一个对象目标中

const assigns = {
    a: 123,
    b: 456
};
const target = {
    a: 456,
    c: 789
}
let result = Object.assign(target, assigns) //参数1是目标对象,参数2是源对象
console.log(result) // {a: 123, b: 456, c: 789}
console.log(result === target) //true 返回的值为目标对象,并没有改变对象的地址

function funs(obj) {
    // obj.name = 'name1'
    // console.log(obj)
    let objs = Object.assign({}, obj) //新的内存地址,不会覆盖obj1
    objs.name = 'name1'
    console.log(objs)
}
const obj1 = {name: 'glob obj'}
funs(obj1)

Proxy

Proxy(代理对象)用于监视对象的操作过程,是以非侵入的方式监听
defineProperty只能监听对象的读写

const person = {
    name: 'name',
    age: 10
}
const personPoxy = new Proxy(person, {
    //监视代理目标属性的访问
    get(target, property) {
        //target为代理目标对象,外部访问的property属性名
        console.log(target, property);
    },
    //监视代理目标设置属性的过程
    set(target, property, value) {
        //target为代理目标对象,外部设置的property属性名, value为设置的属性值
        console.log(target, property, value);
        target[property] = value;
    },
    //监视代理目标删除操作
    deleteProperty(target, property) {
        //target为代理目标对象,property要删除的属性名
        console.log('delet:', property);
        delete target[property]
    }
}) //第一个参数是需要代理的目标对象, 第二个参数是代理的处理对象
console.log(personPoxy.name)
personPoxy.sex = '女';
console.log(person)
delete personPoxy['sex']
console.log(person)

//监视数组
const list = []
const proxyList = new Proxy(list, {
    //用于监视数组的写入操作
    set(target, property, value) {
        //property此时对应的是数组的下标
        console.log('set', property, value)
        target[property] = value
        return true //表示写入成功
    }
})
proxyList.push(100)

除此之外还有更多的操作监听。

Reflect

Reflect封装了对对象的底层操作,不能通过new实例化一个方法,只能调用他封装的方法
Reflect成员方法就是proxy处理对象的默认实现
意义在于提供了一套统一操作对象的api(一共13个)

const obj = {
    name: 'zzz',
    age: 10
}
console.log(Reflect.has(obj, 'name'))
console.log(Reflect.deleteProperty(obj, 'age'))
console.log(Reflect.ownKeys(obj))

class类

function Person(name) {
    this.name
}
Person.prototype.say = function() {
    console.log('say')
}

class Person {
    constructor(name) {
        this.name = name
    }

    say() {
        console.log('say'+this.name)
    }

    //静态方法,用于创建Person类型的实例
    static create(name) {
        return new Person(name)
    }
}
// const p = new Person('tom')
// p.create()
const tom = Person.create('tom') //由于静态方法是挂载到类型上面的,所以静态方法的内部的this指向的是当前的类型,而不是一个新的实例对象
tom.say()

静态方法

类型中的方法一般分为实例方法和静态方法
实例方法:需要通过这个类型构造的实例对象去调用
静态方法:直接通过类型本身去调用,实例化对象无法访问,new一个实例化对象不会被继承这个静态方法

参考代码参照上面class模块

继承

class Person {
    constructor(name) {
        this.name = name
    }

    say() {
        console.log('say'+this.name)
    }
}

class Student extends Person {
    constructor(name, number) {
        //super指向父类,调用他等于调用父类的构造函数
        super(name);
        this.number = number;
    }

    hello () {
        //调用父类的方法
        super.say();
        console.log('my number is', this.number)
    }
}
const s = new Student(1414)
s.hello()

Set

Set是一个类型,通过实例可以调用。用于存放不重复的数据
Set最常用的用途是给数组去重

const s = new Set();
//add方法会返回集合对象本身,所以可以链式调用,添加过程中重复的值会被忽略
s.add(1).add(2).add(3).add(1)
s.size//获取数组长度
s.has(100) //false
s.delete(1) //true
s.clear() //清除

const arr = [1,2,1,2,4,5,7,5]
const result1 = new Set(arr)
const result2 = Array.from(new Set(arr))
const result3= [...new Set(arr)]

Map

和对象相似,但对象的键值对的键只能是字符串类型
对象中如果是非字符串类型作为键,会被toString转译。

const obj = {}
obj[true] = 'value'
obj[123] = 'value'
obj[{a: 1}] = 'value'
//被toString转换,object对象作为键的话全部都被转译成了'[object Object]'
console.log(Object.keys(obj)) //[ '123', 'true', '[object Object]' ]

const m = new Map()
const tom = {name: 'tom'}
m.set(tom, 90)
m.get(tom) //90

Symbol

由于大量引入第三方模块,很有可能出现值相同互相覆盖的情况,这个时候引用了Symbol,Symbol表示一个独一无二的值。symbol是一个数据类型。
对象可以用string和symbol作为键。
当对象用作symbol作为键时,则这个属性变成了对象的私有成员,因为是独一无二的,所以无法在外界访问到。

const s = Symbol('abc')//参数是对当前symbol的描述文本,对象可以用string和symbol作为键
console.log(typeof s)// --> symbol
//在全局对象中复用一个相同的symbol值,for方法传入的值必须是字符串,若不是则会自动转成字符串
const s1 = Symbol.for('123')
const s2 = Symbol.for('123')
console.log(s1===s2)//true
const obj = {
	[Symbol.toStringTag]: 'Xobj'
}
console.log(obj.toString()) //[object Xobj]

for…of循环

for循环适合遍历数组
for…in适合遍历键值对
for…of可以遍历任何数据结构,但是object对象不能直接遍历,因为object对象没有迭代器,需要自己手动写一个迭代器才可以进行遍历,能直接遍历的有数组,Set,Map对象

const arr = [100, 200, 300, 400]
for(const item of arr) {
    // console.log(item) //数组中的每个值
    if(item > 200) {
        // break; 可以用break跳出for...of循环
    }
}
const m = new Map()
m.set('a',10)
m.set('b',20)
for(const [key, value] of m) {
    //map对象遍历每个是键值对的数组
    console.log(key, value)
}

可迭代接口Iterator

const set = new Set(['foo', 'bar', 'baz'])
const iterator = set[Symbol.iterator]() //执行set对象自带的iterator方法,成为迭代器
console.log(iterator.next()) //迭代器的next方法{ value: 'foo', done: false }
console.log(iterator.next()) //迭代器的next方法
console.log(iterator.next()) //迭代器的next方法

只有有symbol.ierator方法的数据结构才可以被迭代,进行for…of遍历

实现可迭代接口

即有Symbol.iterator方法。
迭代器的应用:对外统一迭代接口,让外部不需要再去遍历特定的对象

const obj = {
    //可迭代接口iterable
    [Symbol.iterator]: function () {
        return {
            //迭代器iterator
            next: function() {
                //迭代结果iterationResult
                return {
                    value: 'zc',
                    done: true
                }
            }
        }
    }
}

//举例
const obj = {
    store: ['aaa', 'bbb', 'ccc'],
    //可迭代接口iterable
    [Symbol.iterator]: function () {
        let this_ = this
        let index = 0
        return {
            //迭代器iterator
            next: function() {
                //迭代结果iterationResult
                const result = {
                    value: this_.store[index],
                    done: this_.store.length >= index ? false : true
                }
                index ++ 
                return result
            }
        }
    }
}
for(const item of obj) {
    console.log(item)
}   
//对外统一迭代接口,让外部不需要再去遍历特定的对象
const todos = {
    life: ['吃饭', '睡觉', '打豆豆'],
    learn: ['语文', '数学', '外语'],
    works: ['喝茶'],

    [Symbol.iterator]: function() {
        const all = [...this.life, ...this.learn, ...this.works]
        let index = 0
        return {
            next: function () {
                return {
                    value: all[index],
                    done: index++ >= all.length
                }
            }
        }
    }
}
for(const item of todos) {
    console.log(item)
}

Generator生成器

Generator生成器:避免异步编程中,回调嵌套过深,提供更好的异步解决办法

yield后面的值将作为next()的结果返回

function * foo() {
    console.log(1111)
    yield 100;
    console.log(222)
    yield 200;
    console.log(333)
    yield 300;
}
const generator = foo()
console.log(generator.next()) //111 { value: 100, done: false }
console.log(generator.next()) //222 { value: 200, done: false }
console.log(generator.next()) //333 { value: 300, done: false }
console.log(generator.next()) // { value: undefined, done: true }

Generator生成器的应用

1.可用作发号器

function * createIDMaker () {
    let id = 1
    while (true) {
        yield id++
    }
}
const idMaker = createIDMaker()
console.log(idMaker.next().value)

2.使用generator函数生成iterator迭代器

const todos = {
    life: ['吃饭', '睡觉', '打豆豆'],
    learn: ['语文', '数学', '外语'],
    works: ['喝茶'],

    [Symbol.iterator]: function * () {
        const all = [...this.life, ...this.learn, ...this.works]
        for(const item of all) {
            yield item
        }
    }
}
for(const item of todos) {
    console.log(item)
}

ECMAScript2016

数组的indexof()方法查找返回元素的下标,但如果是查找NaN类型,则查找不到。
1.ES6新增了一个includes方法,返回值为布尔类型,可以查找NaN类型。
2.新增指数运算符,如2的十次方写作: 2**10

ECMAScript2017

Object.values(obj) 返回值的数组
Object.entries(obj) 对象键值对组成一个个数组之后,返回全部的键值对数组
Object.getOwnPropertyDescriptors(obj) 获取对象中的所有描述
string.padEnd(),string.padStart()

const obj = {
    foo: 'value1',
    bar: 'value2'
}
console.log(Object.values(obj)) //[ 'value1', 'value2' ]
console.log(Object.entries(obj)) //[ [ 'foo', 'value1' ], [ 'bar', 'value2' ] ]
for( const [key, value] of Object.entries(obj)) {
    console.log(key, value)
}
//这里由于与Map对象的返回值相同,所以可以转化为Map对象
console.log(new Map(Object.entries(obj)))



const p1 = {
    firstName: 'value1',
    lastName: 'value2',
    get fullName () {
        return this.firstName + this.lastName
    }
}
// const p2 = Object.assign({}, p1);
// p2.firstName = 'aaa'
// //set方法无法复制
// console.log(p2)

const description = Object.getOwnPropertyDescriptors(p1)
console.log(description)
const p2 = Object.assign({}, description)
console.log(p2)

const books = {
    html: 5,
    css: 16,
    javascript: 120
}
for(const [key, value] of Object.entries(books)) {
//第一个是总体字符长度,第二个参数是填充内容
    console.log(`${key.padEnd(16, '-')}|${value.toString().padStart(3, '0')}`)
}
//html------------|005
//css-------------|016
//javascript------|120

这一模块遇见的问题:

  1. package.json和package-lock.json问题
    这个其实是Npm5之后,npm install 都会有一个package-lock.json文件,原来package.json文件只能锁定大版本,也就是版本号的第一位,并不能锁定后面的小版本,每次npm install都是拉取的该大版本下的最新的版本。package-lock.json功能,为的是让开发者知道只要你保存了源文件,到一个新的机器上、或者新的下载源,只要按照这个package-lock.json所标示的具体版本下载依赖库包,就能确保所有库包与你上次安装的完全一样。
  2. 闭包
    闭包函数:声明在一个函数中的函数,叫做闭包函数。
    闭包:内部函数总是可以访问其所在的外部函数中声明的参数和变量,即使在其外部函数被返回(寿命终结)了之后。