es6+的一些新特性

文章内容输出来源:拉勾教育前端高薪训练营

1.ES6+的一些新特性

1.1 let、const、var
  • 变量提升:var会产生变量提升效果,使用undefined初始化变量值,可以在声明前访问,在声明前访问输出undefined;let和const仅在自身作用域内提升,并且不会挂载到window上,但是会有TDZ暂时性死区,在声明前访问会报错,只能在声明之后访问
  • 作用域:由于var会产生变量提升,所以会有全局作用域;let和const的作用域仅限于自身声明的代码块内
  • 初始化:var和let都可以仅声明,不进行初始化值;const必须在声明的同时初始化值
  • 重新定义:var在第一次声明定义后,可以重新进行多次声明定义;let和const在同一作用域下只能被声明定义一次
  • 多次赋值:var和let可以进行多次赋值;const基础数据类型不能多次赋值,引用数据类型可以改变其内部的属性值
1.2 数组和对象的解构
/* 数组解构 */
const arr = [100, 200, 300]
const [foo, bar, baz] = arr
console.log(foo, bar, baz)

const [, , baz] = arr
console.log(baz)

const [foo, ...rest] = arr
console.log(rest)

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

const [foo, bar, baz = 123, more = 'default'] = arr
console.log(baz, more)

/* 对象解构 */
const obj = { name: 'zce', age: 18 }
const { name } = obj
console.log(name)

const age = 28
const { age: objAge } = obj
// const { age: objAge = 18 } = obj
1.3 模板字符串
  • 模板字符串支持换行操作
const str = `hello 
world
`
// hello 
// world
  • 支持变量,插值操作${name} ${1 + 2}
console.log(`${1 + 2}`) // 3
  • 支持标签函数
// 标签函数
const name1 = 'tom'
const gender = false
function myTagFunc (strings, name, gender) {
  const sex = gender ? 'man' : 'woman'
  return strings[0] + name + strings[1] + sex + strings[2]
}
const r = myTagFunc`hey, ${name1} is a ${gender}`
console.log(r) // hey, tom is a woman
1.4 字符串扩展方法
const msg = 'Error: foo is not defined.'
console.log(msg.startsWith('Error')) // true,字符串以Error开始
console.log(msg.endsWith('Error')) // false,字符串以Error结束
console.log(msg.includes('foo')) // true,字符串包含foo
1.5 参数默认值,剩余参数
// es5参数默认值
function foo1 (enable) {
  // enable = enable || true // 短路运算符,在传入false时会出问题,此时会变成true
  enable = enable === undefined ? true : enable // 三元运算替代短路运算
  console.log(enable)
}
// es6参数默认值
function foo2 (enable = true) {
  console.log(enable)
}

// es5剩余参数,arguments伪数组
function foo3 () {
  console.log(arguments)
}
// es6剩余参数,只能出现在型参最后一位,并只能使用一次
function foo4 (...args) {
  console.log(args)
}
1.6 展开数组
const array = [1, 2, 3, 4, 5, 6]
console.log(...array) // 1 2 3 4 5 6

2.箭头函数

箭头函数this根据外层(函数或者全局)上下文来决定,指向为外层this的指向。

const obj = {
  name: '123',
  a () {
    console.log(this)
  },
  b: () => {
    console.log(this)
  },
  c () {
    setTimeout(() => {
      console.log(this)
      setTimeout(() => {
        console.log(this)
      }, 1000);
    }, 1000);
  },
  d: () => {
    setTimeout(() => {
      console.log(this)
    }, 1000);
  }
}

obj.a() // obj
obj.b() // window
obj.c() // obj obj
obj.d() // window

3.对象的一些应用

3.1 对象字面
const bar = '123'
const o = {
  foo: '123',
  bar, // 对象字面量
  method1 () {
    console.log(this)
  },
  [Math.random()]: '123' // 计算属性名
}
3.2 object.assign

拷贝对象,但是只能拷贝一层数据,深层数据还是同一内存地址。

const assignA = {
  a: 123,
  b: 456,
  c: {
    a: 1,
  }
}

function f (obj) {
  const o = Object.assign({}, obj)
  o.c = 'aaa'
  console.log(o) // {a: 123, b: 456, c: "aaa"}
}
f(assignA)
console.log(assignA) // 不会被改变
const assignA = {
  a: 123,
  b: 456,
  c: {
    a: 1,
  }
}

function f (obj) {
  const o = Object.assign({}, obj)
  o.c.a = 'aaa'
  console.log(o) // {a: 123, b: 456, c: { a: aaa }}
}
f(assignA)
console.log(assignA) // c.a会被改变成aaa
3.3 object.is

判断两个值是否相等

console.log(0 == false) // 两等自动转换数据类型,输出true
console.log(0 === false) // 三等不会自动转换数据类型输出false,但是不能判断正负,会出现 -0 === +0 为true
console.log(NaN === NaN) // false
Object.is(NaN, NaN) // true

4.Proxy代理

和defineProperty比较,defineProperty只能监视属性的读写,Proxy可以监视到更多操作,例如delete和对象方法调用等,Proxy是非侵入的方式监管对象

Proxy的一些方法(handler方法 => 触发方式)

  • get => 读取某个属性
  • et => 写入某个属性
  • as => in 操作符
  • eleteProperty => delete 操作符
  • etPrototypeOf => Object.getPrototypeOf()
  • etPrototypeOf => Object.setPrototypeOf()
  • sExtensible => Object.isExtensible()
  • erventExtensions => Object.perventExtensions()
  • etOwnPropertydescriptor => Object.getOwnPropertydescriptor()
  • efineProperty => Object.defineProperty()
  • wnKeys => Object.getOwnPropertyNames()、Object.getOwnPropertySymbols()
  • pply => 调用一个函数
  • onstruct => 用 new 调用一个函数
const obj = {
  a: 123,
  b: 456,
  c: {
    a: 1,
  }
}

const proxyObj = new Proxy(obj, {
  get (target, property) {
    console.log(target, property)
    return property in target ? target[property] : 'defaultValue'
  },
  set (target, property, value) {
    if (property === 'a' && !Number.isInteger(value)) {
      throw new TypeError(`${value} is not an int`)
    }
    target[property] = value
  },
  deleteProperty (target, property) {
    console.log(target, property)
    if (property === 'a') {
      throw new Error(`${property} can not be deleted`)
    }
    delete target[property]
  }
})
delete proxyObj.b
console.log(proxyObj)

5.Reflect

Reflect 统一的对象操作API

  • 是一个静态类,不能用new Reflect()
  • Reflect成员方法就是Proxy处理对象的默认实现
  • 可以用来统一对象属性操作的风格
const obj = {
  a: 123,
  b: 456,
  c: {
    a: 1,
  }
}

const proxyObj = new Proxy(obj, {
  get (target, property) {
    console.log(target, property)
    return Reflect.get(target, property)
  }
})
console.log(proxyObj.a)

// console.log('a' in obj)
console.log(Reflect.has(obj, 'a'))
// console.log(delete obj['a'])
console.log(Reflect.deleteProperty(obj, 'a'))
// console.log(Object.keys(obj))
console.log(Reflect.ownKeys(obj))

6.class 类

  • 实例方法是通过类构造的实例对象去调用
  • 静态方法是类本身调用的方法:static静态方法,static方法中的this不会指向实例,而是指向类型
  • 类的继承使用extends
// es5中的类
function Person (name) {
  this.name = name
}
Person.prototype.say = function () {
  console.log(`hi, ${this.name}`)
}
// es6中的类
class Person {
  constructor (name) {
    this.name = name
  }

  say () {
    console.log(`hi, ${this.name}`)
  }

  static create (name) {
    // console.log(this) // this指向类型本身
    return new Person(name)
  }
}

class Student extends Person {
  constructor (name, number) {
    super(name) // super方法指向父类,调用即调用父类构造函数
    this.number = number
  }

  hello () {
    super.say() // super调用父类的方法
    console.log(`my number is ${this.number}`)
  }
}

const p = new Person('mike')
const p1 = Person.create('tom')
const s = new Student('jack', 10)
p.say()
p1.say()
s.hello()

7.set和map

/*
  Set集合,里面不能存在重复的数据
*/

const s = new Set()
s.add(1).add(2).add(3).add(1)
console.log(s) // Set(3) {1, 2, 3}

s.forEach(i => console.log(i)) // 1 => 2 => 3

for (let i of s) {
  console.log(i) // 1 => 2 => 3
}

console.log(s.size) // 长度3
console.log(s.has(1)) // true
s.delete(3) 
console.log(s) // Set(2) {1, 2}

s.clear()
console.log(s) // Set(0) {}

const arr = ['a', 'b', 'c', 'a']
const r = [ ...new Set(arr) ]
console.log(r) // ["a", "b", "c"]
/*
  Map对象,可以使用任意数据类型作为键,普通对象只能使用字符串作为键
*/

// 普通对象
const obj = {}
obj[true] = 'true'
obj[12] = '12'
obj[{ a: 1 }] = 'aaa'

console.log(Reflect.ownKeys(obj)) // ["12", "true", "[object Object]"]

// Map对象
const m = new Map()
const tom = { name: 'tom' }
m.set(tom, 90)
m.set(true, true)
m.set(12, 12)
m.forEach((val, key) => {
  console.log(val, key) // 90 {name: "tom"} => true true => 12 12
})
console.log(m) // Map(3) {{…} => 90, true => true, 12 => 12}
console.log(m.get(tom)) // 90
console.log(m.has(tom)) // true
m.delete(tom)
console.log(m) // Map(2) {true => true, 12 => 12}
m.clear()
console.log(m) // Map(0) {}

8.Symbol

Symbol数据类型,为对象添加独一无二的属性名。
在Symbol出现前,对象属性名都是字符串,这容易造成属性名的冲突,比如他人写了一个对象,你在使用此对象时,想为这个对象添加一个新的方法名称,就可能与现有方法名称产生冲突。
而Symbol的出现恰恰解决了这种冲突,就算声明两个同样的变量,除非使用Symbol.for,不然也不会相等

const id = Symbol()
const name = Symbol('name')
const _name = Symbol('name')
const age = Symbol('age')
const obj = {
  [name]: 'jimmy',
  say () {
    console.log(this[name]) // jimmy
  },
  s: 's'
}

obj[_name] = 'jim'
obj[id] = 1
obj[age] = 20

console.log(obj) // {s: "s", Symbol(name): "jimmy", Symbol(name): "jim", Symbol(): 1, say: ƒ, …}
obj.say()

// for in 循环无法获取,Object.keys,jSON.stringify无法获取对象的Symbol属性
for (const key in obj) {
  console.log(key) // say => s
}
console.log(Object.keys(obj)) // ["say", "s"]
console.log(JSON.stringify(obj)) // {"s":"s"}

// 获取对象的Symbol属性
console.log(Reflect.ownKeys(obj)) // ["say", "s", Symbol(name), Symbol(name), Symbol(), Symbol(age)]
console.log(Object.getOwnPropertySymbols(obj)) //  [Symbol(name), Symbol(name), Symbol(), Symbol(age)]

// 同样的Symbol声明不相等
console.log(Symbol() === Symbol()) // false
// 可以使用Symbol.for来相等,会将传入的属性值转为字符串类型
const s1 = Symbol.for('s')
const s2 = Symbol.for('s')
console.log(s1 === s2) // true
console.log(Symbol.for(true) === Symbol.for('true')) // true

9.for of

for of 遍历所有数据结构的统一方式,被遍历的数据需要具备Symbol.iterator属性

const arr = [1, 2, 3, 4, 5, 6]

const s = new Map()
s.set('foo', 'foo')
s.set('bar', 'bar')
for (const item of arr) {
  console.log(item) // 1 => 2 => 3
  if (item === 3) break
}

for (const [key, value] of s) {
  console.log(key, value) // foo foo => bar bar
}

10.iterator迭代器

const arr = [1, 2, 3]
const iterator = arr[Symbol.iterator]() // 可遍历数据都有一个Symbol[iterator]属性
console.log(iterator.next()) // {value: 1, done: false}
console.log(iterator.next()) // {value: 2, done: false}
console.log(iterator.next()) // {value: 3, done: false}
console.log(iterator.next()) // {value: undefined, done: true}

// 实现迭代器让for...of来遍历对象
const obj = {
  life: ['打游戏', '看书', '喝茶'],
  learn: ['js', 'css', 'html'],
  work: ['study']
}
obj[Symbol.iterator] = function () {
  const keys = Object.keys(this)
  let count = 0
  return {
    next () {
      return { value: [keys[count], obj[keys[count]]], done: count++ >= keys.length }
    }
  }
}
const o = obj[Symbol.iterator]()

for (const [key, val] of obj) {
  console.log(key, val) // life (3) ["打游戏", "看书", "喝茶"] => learn (3) ["js", "css", "html"] => work ["study"]
}

11.generator生成器

  • 避免异步编程中回调嵌套过深
  • 惰性执行,yield之后需要调用next()来继续执行
// 生成器模拟发号器
function * createMaker () {
  let id = 1
  while (true) {
    yield id++
  }
}

const idMaker = createMaker()
console.log(idMaker.next().value) // 1
console.log(idMaker.next().value) // 2
console.log(idMaker.next().value) // 3

// 实现生成器让for...of来遍历对象
const obj = {
  life: ['打游戏', '看书', '喝茶'],
  learn: ['js', 'css', 'html'],
  work: ['study']
}
obj[Symbol.iterator] = function * () {
  const keys = Object.keys(this)
  for (const item of keys) {
    yield [item, obj[item]]
  }
}

for (const [key, val] of obj) {
  console.log(key, val) // life (3) ["打游戏", "看书", "喝茶"] => learn (3) ["js", "css", "html"] => work ["study"]
}

12.es2016和es2017新增属性

/*
  es2016新增两个新属性
  * Array.prototype.includes 判断数组是否包含某个值
  * 指数运算符 x ** y
*/

const arr = ['f', 1, NaN, false]

console.log(arr.indexOf('f'))
console.log(arr.indexOf(1))
console.log(arr.indexOf(NaN)) // indexOf不能识别
console.log(arr.indexOf(false))
console.log(arr.includes(NaN)) // includes可以识别

console.log(Math.pow(2, 10)) // Math的指数运算
console.log(2 ** 10) // es2016的指数运算
/*
  es2017新增五个新功能
  * Object.values,遍历对象的所有值
  * Object.entries,将数组的键值对以数组形式返回,从而可以用for of来遍历
  * Object.getOwnPropertyDescriptors,可以复制Object.assign不能复制的对象中的getter和setter,Object.assign
  * String.prototype.padStart / String.prototype.padEnd 字符串填充
  * 在函数的参数中添加尾逗号
*/

// Object.values Object.entries
const obj = {
  a: 1,
  b: 2,
  get sum () {
    return this.a + this.b
  }
}
console.log(Object.values(obj))
console.log(Object.entries(obj))
console.log(new Map(Object.entries(obj)))

// Object.getOwnPropertyDescriptors
const obj1 = Object.assign({}, obj)
obj1.a = 3
console.log(obj1.sum)
const desc = Object.getOwnPropertyDescriptors(obj)
const obj2 = Object.defineProperties({}, desc)
obj2.a = 3
console.log(obj2.sum)

// String.prototype.padStart / String.prototype.padEnd 
const books = {
  html: 5,
  css: 16,
  javascript: 128
}

for (const [key, val] of Object.entries(books)) {
  console.log(`${key.padEnd(16, '-')}|${val.toString().padStart(3, '0')}`)
}

// 在函数的参数中添加尾逗号
function foo (
  a,
  b,
) {}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值