字符串的扩展方法

const message = `Error: foo is not defined.`
console.log(message.startWith('Error')) // true
console.log(message.endWith('.')) // true
console.log(message.includes('foo')) // true

参数默认值

function foo(enable=true) {
  console.log(enable)
foo() // true
function foo (...args) { // 只能出现在形参的最后一位,只能使用一次
  console.log(args)
foo([1,2,3])

spread 展开数组

const arr = ['a','b','c']
console.log(...arr)
function inc (number) {
  return number + 1
const inc = (m,n)=> m+n
console.log(inc(1,3)) // 3
// 不会改变this的指向
const person = {
  name: 'tom',
  say: ()=>{
    console.log(this.name)
  sayAsync: function() {
    setTimeout(()=>{
      console.log(this.name)
person.say() // undefined 

对象字面量的增强

const obj = {
  name:'zhangsan',
  foo(){ // 等价于:function声明
  [name]:100 // 变量名也可动态

对象扩展方法

Object.assign(obj, target) // 后面对象覆盖前面的
Object.is(+0, -0) // true
Object.is(NaN, NaN) // true
// Object.definedProporty() 只能监听到对象的读写 对数组的监听是重写方法$set

Proxy

// 能监视到更多对象操作 或对对象方法的调用 更好的支持数组监听 是以非侵入方式监管对象的读写

const person = {
  name:'aaa',
  age: 90
const personProxy = new Proxy(person, {
  get(target, property) {
    return property in target ? target[property] : 'default'
    console.log(target, property)
    // return 10
  set(target, property, value) {
    if(property==='age') {
      if(!Number.isInteger(value)) {
        throw new TypeError(`${value} is not an int`)
    target[property] = value
    console.log(target, property, value)
personProxy.age = 25
personProxy.gender = true
// console.log(personProxy.name) // 10
// console.log(personProxy.name) // aaa
const list = []
const listProxy = new Proxy(list, {
  set (target, property, value) {
    console.log('set', property, value)
    target[property] = value
    return true
listProxy.push(100)

Reflect

// 统一的对象操作API 内部封装了一系列对对象的底层操作 成员方法就是Proxy对象中对应的方法

const obj = {
  name:'aaa',
  age: 90
// console.log('name' in obj)
// console.log(delete obj.age)
// console.log(Object.keys(obj))
console.log(Reflect.has(obj, 'name'))
console.log(Reflect.deleteProperty(obj, 'age'))
console.log(Reflect.ownKeys(obj))

Promise

class 类

function Person(name) {
  this.name = name
class Person {
  constructor(name) {
    this.name = name
  say() {
    console.log(this.name)
  static create(name) { // 静态成员 static
    return new Person(name)
const n = new Person('SUMMER')
const tom = Person.create('tom') 
tom.say()
// 类的继承
class Student extends Person { // 继承person所有参数
  constructor(name, number) {
    super(name) // 调用它就是调用父类的所有方法
    this.number = number
  hello() {
    super.say()
    console.log(this.number)
const s = new Student('tom', 100)
console.log(s)

Set 数据结构 集合

const s = new Set()
s.add(1).add(2).add(3)
s.forEacg(i=>console.log(i))
s.size
s.has(100) // false
s.delete(3)
s.clear()
// 数组去重 new Set
const arr = [1,2,1,3,4,5]
const result = Array.from(new Set(arr))
const result = [...new Set(arr)]

// 可以把Object作为键 对象只能用字符串做键

const obj = {}
obj[true] = 'value'
obj[123] = 'value'
obj[{a:1}] = 'value'
const m = new Map()
const tom = {name: 'tom'}
m.set(tom, 90)
console.log(m)
m.has()
m.delete()
m.clear()
m.forEach((value,key)=>{
  console.log(key)

Symbol // 表示一个独一无二的值

// 通过Symbol创建的值都是独一无二的
// 可以作为对象的属性名
// 创建私有成员

Iterator

// for of 循环 可以遍历所有的有Iterator的
const arr = [1,2,3]
for(const item of arr) {
  console.log(item)
// 实现可迭代接口 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('循环体')
// 作用:对外提供统一遍历接口 适合于任何数据结构

生成器 generator 异步编程解决方案

function * foo () {
  console.log('111')
  yield 100
  console.log('222')
  yield 200
  console.log('333')
  yield 300
const res = foo()
console.log(res) // 打印生成器对象
console.log(res.next()) // 实现了迭代器接口
const generator = foo()
console.log(generator.next()) // 遇到yield暂停 111 {value: 100, done: false}
console.log(generator.next()) // 遇到yield暂停 222 {value: 200, done: false}
console.log(generator.next()) // 遇到yield暂停 333 {value: 300, done: false}
console.log(generator.next()) // 遇到yield暂停  {value: undefined, done: true}

生成器应用

案例:使用generator函数实现iterator方法

const todos = {
  life: ['吃饭','睡觉'],
  learn: ['学习'],
  work: ['摸鱼'],
  [Symbol.iterator]: function * () {
    const all = [...this.life, ...this.learn, ...this.work]
    for (const item of all) {
      yield item
for (const item of todos) {
  console.log(item)

ECAMAScript2016

includes

[1,2,3].includes(2) // true
[1,2,3].includes(NaN) // false

指数运算符

console.log(Math.pow(2,3)) // 以前指数运算
console.log(2 ** 10) // 现在指数运算

ECAMAScript2017

Object.values、Object.entries

Object.values(obj)
Object.entries(obj)
new Map(Object.entries(obj))

getOwnPropertyDescriptors

const p1 = {
  firstName: 'lei',
  lastName: 'wang',
  get fullName() {
    return this.firstName+' '+this.lastName
console.log(p1.fullName)
const p2 = Object.assign({}, p1) // 复制的时候值当做普通属性复制
p2.firstName = 'zhangsan'
console.log(p2) // 打印的还是p1内容
const desc = Object.getOwnPropertyDescriptors(p1)
console.log(desc)
const p2 = Object.definedPropories({}, desc)
p2.firstName = 'zhangsan'
console.log(p2.fullName)

padStart/padEnd 补齐

const books = {
  html: 3,
  css: 10,
  javascript: 120
for(const [name, count] of Object.entries(books)) {
  console.log(`${name.padEnd(16, '-')}|${count.toString().padStart(3, '0')}`)

函数参数中添加尾逗号

function foo (
  bar, baz,) {

TypeScript

TypeScript解决JavaScript类型系统的问题
编程语言从类型安全角度分为强类型与弱类型
从类型检查角度分为静态类型与动态类型
强类型不允许任意类型的隐式类型转换 // 编译阶段就不允许
静态类型一个变量声明是就是确定的,并且不允许修改

强类型优点

  • 错误更早暴露
  • 代码更智能,编码更准确
  • 重构更牢靠
  • 减少不必要的类型判断
  • const hello = (name: string) => {
      console.log(name)
    console.log('jdsodj')
    
    const a: string = ''
    const b: number = 1
    const c: boolean = true
    const d: void = undefined
    const e: null = null
    const f: undefined = undefined
    
    enum postStatus {
        startus0 = 0, // 如果是数字还会自增
        startus1,
        startus2
    // postStatus[0]
    // postStatus.startus0
    

    函数类型 FunctionType

    const s = (name: string, age?: number) => {
      console.log(name+age)
    s('hahha')
    

    隐式类型推断

    let age = 10 // 推断为number
    let foo // 推断为any 
    

    类型断言 as <>

    const nums = [1,2,3]
    const res = nums.find(i=>i>0)
    const num = res as number
    const num2 = <number>res  // <> jsx下冲突 建议用as
    

    接口 interface 约束对象的结构

    interface Post {
        title: string
        num: number
        subtitle?: string // 可选成员
        readonly summary: string // 只读成员
    function printPost(post: Post) {
      console.log(post.title)
      console.log(post.num)
    printPost({
      title: 'ahhha',
      num: 1000,
      summary: 'ok'
    

    类 - 描述一类事物的具体特征 ts增强了class的语法

    class Person {
      public name: string // 默认public
      age: number
      private weight: number  // 私有属性
      protected readonly gender: boolean  // protected只允许在子类中访问的成员 readonly只读
      constructor (name: string, age: number) { // 构造函数也可设置为private protected
        this.name = name
        this.age = age
      say(msg: string):void {
        console.log(`${this.name}: ${this.age}${msg}`)
    class Student extends Person {
      constructor(name: string, age: number) {
        super(name, age)
        console.log(this.gender)
    

    implements 扩充

    interface Eat {
      eat (food: string): void
    interface Run {
      run (distance: number): void
    class Dog implements Eat, Run {
      eat (food: string):void {
        console.log(food)
     run (distance: number):void {
        console.log(distance)
    class Pig implements Eat, Run {
      eat (food: string):void {
        console.log(food)
     run (distance: number):void {
        console.log(distance)
    

    抽象类 -只能被继承

    abstract class Animal {
      eat(food: string):void {
        console.log(food)
      abstract run (distance: number): void
    

    泛型 定义的时候不指定类型 调用的时候再确定类型

    function createArr<T> (length: number, value: T): T[] {
      const arr = Array<T>(length).fill(value)
      return arr