ECMAScript2015(ES6)新特性

98 阅读6分钟

面向过程与面向对象

面向过程:

  1. 打开冰箱门
  2. 把大象装进去
  3. 关上冰箱门

面向对象:

  1. 大象
  2. 冰箱
  3. 隐藏对象

javaScript是一种基于对象(object-based)的语言

类与对象

类(calss) 是对象(object)的模板,定义了同一组对象共有的属性和方法。

ES5中的类与继承

// 定义类
function People (name, age) {
    //实例属性
    this.name = name;
    this.age = age;
}
//实例方法
People.prototype.showName = function () { 
    console.log('我的名字是'+this.name);
}

//静态属性
People.count = 0
// 静态方法
People.getCount = function () { 
    // this 静态方法中的this指向类本身,而不是实例 console.log(this) //undefined
    return People.count
}

ES5中实现继承: 构造函数继承:只能继承父类的属性,继承不了父类的方法

//父类
function Animal (name) {
    this.name = name
}

Animal.prototype.showName = function () { 
    console.log('名字是:', this.name);
}

// z子类    
function Dog (name, color) {
    Animal.call(this, name) //继承实例属性
    this.color = color
}

let d1 = new Dog('wangcai', 'yellow')
console.log(d1.showName(), 'dddd'); // d1.showName is not a function

原型继承: 只能继承方法,继承不了父类的属性

//父类
function Animal (name) {
    this.name = name
}

Animal.prototype.showName = function () { 
    console.log('名字是:', this.name);
}

// z子类    
function Dog (name, color) {
    // Animal.call(this, name) //继承实例属性
    this.color = color
}

Dog.prototype = new Animal() //继承父类方法
Dog.prototype.constructor = Dog //修正constructor 

let d1 = new Dog('wangcai', 'yellow')
console.log(d1.showName(), 'dddd'); // 名字是: undefined

组合式继承:

//父类
function Animal (name) {
    this.name = name
}

Animal.prototype.showName = function () { 
    console.log('名字是:', this.name);
}

// z子类    
function Dog (name, color) {
    Animal.call(this, name) //继承实例属性
    this.color = color
}

Dog.prototype = new Animal() //继承父类方法
Dog.prototype.constructor = Dog //修正constructor 

let d1 = new Dog('wangcai', 'yellow')
console.log(d1.showName()); // 名字是: wangcai

ES6中定义类:

// ES6中的类

class People {
    constructor(name, age) {
        this.name = name
        this.age = age
    }
    showName() {
        console.log('我的名字是'+this.name)
    }
}

let p1 = new People('a', 18)

ES6继承:extends

class People {
    constructor(name, age) {
        this.name = name
        this.age = age
    }
    showName() {
        console.log('我的名字是'+this.name)
    }
}

let p1 = new People('a', 18)
// console.log(p1)

class Coder extends People {
    constructor(name, age, company) {
        super(name, age)
        this.company = company
    }
    showCompany() {
        console.log('我的公司是'+this.company)
    }
}

let c1 = new Coder('b', 20, 'baidu')
console.log(c1.showName());

在class内部最顶层定义属性,get,set


class People {
    constructor(name, age) {
        this.name = name
        this.age = age
        this._sex = '-1'
    }
    // 在class内部最顶层定义属性
    get sex () {
        return this._sex
    }
    set sex (val) {
        this._sex = val
    }
    showName() {
        console.log('我的名字是'+this.name)
    }
    // 静态方法
    static getCount() {
        return 5
    }
}
// 静态属性
People.count = 9

Symbol

  • 一种新的原始数据类型
  • 声明方式
  • 应用场景
let s1 = Symbol()
let s2 = Symbol()
console.log(s1 === s2) // false
let s1 = Symbol('s111')
let s2 = Symbol('s222')
console.log(s1 === s2) // false

Symbol for: 全局环境

let s1 = Symbol.for('foo')
let s2 = Symbol.for('foo')
console.log(s1 === s2) //true

const s1 = Symbol('foo')
console.log(Symbol.keyFor(s1)) // undefined

const s2 = Symbol.for('foo')
console.log(Symbol.keyFor(s2)) // foo

Object.getOwnPropertySymbols(xxx): 只能获取到Symbol定义的key Reflect.ownkeys(xxx):可以获得普通属性和Symbol定义的key

应用场景:

const shapeType ={
    triangle:Symbol(),
    circle:Symbol()
}

function getArea(shape){
    let area = 0
    switch(shape){
        case shapeType.triangle:
            area = 1
            break
        case shapeType.circle:
            area = 2
            break
    }
    return area
}

Set

  • 一种新的数据结构
  • 常用方法
  1. 增加:add
  2. 删除:delete
  3. 清空 clear
  4. 是否存在某一个值:has
  5. 大小: size
let s = new Set([1,3,3,4])
  • 遍历
s.forEach(item => console.log(item))
for(let item of s){
    console.log(item)
}
for(let item of s.keys()){
  console.log(item)
}
for(let item of s.values()){
  console.log(item)
}
for(let item of s.entries()){
  console.log(item[0],item[1])
}
  • 应用场景
//数组去重:
let arr = [1,2,3,4,2,3]
let s = new Set(arr)
console.log(s)

// 合并去重
let arr1 = [1,2,3,4]
let arr2 = [2,3,4,5,6]
let s = new Set([...arr1,...arr2])

console.log([...s])//转换为数组
console.log(Array.from(s))

//求交集:
let s1 = new Set(arr1)
let s2 = new Set(arr2)
let result = new Set(arr1.filter(item => s2.has(item)))
console.log(result) //Set(3) {2, 3, 4}
// 求差集
let result2 = new Set(arr1.filter(item => !s2.has(item)))

WeakSet

  • 只能够存储对象
  • 不可以遍历
  • 弱引用,并不会被垃圾回收机制(GC)考虑
let ws = new WeakSet()
ws.add({
 name:'imooc'
})

ws.add({age:5})

ws.delete()

Map

  • 一种新的数据结构(key可以是任意类型)
  • 常用方法
  1. 增加:set
  2. 获取:get
  3. 删除:delete
  4. 大小:size
  5. 是否有: has
// 遍历 forEach
map.forEach((value,key)=>console.log(value,key))

// for of
for(let [key,value] of map){
    consolelog(key,value)
}

for(let key of map.keys()){
    consoel.log(key)
}
for(let value of map.values()){
    consoel.log(value)
}

for(let [key,value] of map.entries()){
    consoel.log(key,value)
}

WeakMap

  • key 必须是引用数据类型
  • 不可以遍历
  • 弱引用

字符串的扩展

image.png

正则表达式的扩展

  • i 忽略大小写修饰符
  • g 全局修饰符
  • m 多行修饰符
  • y 粘连修饰符 const str = 'aaa_aa_a'

const reg1 = /a+/g // 每次匹配剩余的 const reg2 = /a+/y // 剩余的第一个开始匹配

数值的扩展

image.png

// 十进制 -> 二进制
const a = 5 // 101
console.log(a.toString(2)) // 101

// 二进制 ->十进制
const b = 101
console.log(parseInt(b,2))   // 把b当做一个2进制的数去转化

ES6

  • 0B 二进制

  • 0O 八进制

  • Number.isFinite // 判断一个数是不是有限的

  • Number.isNaN

  • Number.isInteger //是否是一个整数

  • Math.pow(2,53) // 整数的最大值 2的53次方,最小值 负2的53次方

  • Math.sign(5) //1

  • Math.sign(-5) //-1

  • Math.sign(0) //0

  • Math.sign(NaN) //NaN

代理Proxy

  • ES5 defineProperty
let obj = {}
let newVal = ''
Object.defineProperty(obj, 'name', {
    get () {
        console.log('get');
        return newVal
    },
    set (val) {
        console.log('set', val);
        newVal = val
    }
})

obj.name = 'newEs'

console.log(obj.name) //newEs
  • ES6 proxy
//基础用法
let obj = {}
let p = new Proxy(obj, {})
obj.name = 'es6 proxy'
console.log(obj.name) //es6 proxy
for (let key in obj) {
    console.log(key,':key'); //name :key
}
  • get
let arr = [7, 8, 9]
arr = new Proxy(arr, {
    get (target, prop) {
        console.log(target, prop);
        return prop in target ? target[prop] : 'error'
    }
})

console.log(arr[1],'===='); // 8
let dict = {
    'hello': '你好',
    'world': '世界'
}

dict= new Proxy(dict, {
    get (target,prop) {
        return prop in target ? target[prop] : prop
    }
})
console.log(dict['world'],'====dict'); //世界
  • set
let arr = []
arr = new Proxy(arr, {
    set (target, prop, val) {
        if (typeof val === 'number') {
            target[prop] = val
            return true
        } else {
            return false
        }
    }
})
arr.push(5)
arr.push(6)
console.log(arr[0]); //5
  • has
let range = {
    start: 1,
    end:5
}

range = new Proxy(range, {
    has (target, prop) {
        return prop >= target.start && prop <= target.end
    }
})

console.log(2 in range); //true
  • ownKeys
let obj = {
    name: 'imooc',
    [Symbol('es')]:'es6'
}

console.log(Object.getOwnPropertyNames(obj)) // [name]
console.log(Object.getOwnPropertySymbols(obj)) // [Symbol(es)]
console.log(Object.keys(obj)) // ['name']
for (let key in obj) {
    console.log(key); //name
}

let userInfo = {
    userName: 'heiheihei',
    age: 34,
    _password:'123'
}

userInfo = new Proxy(userInfo, {
    ownKeys (target) {
        return Object.keys(target).filter(key => !key.startsWith('_'))
    }
})

for (let key in userInfo) {
    console.log(key); //userName,age
}
console.log(Object.keys(userInfo));/ ['userName', 'age']
  • 综合案例
let user = {
    userName: 'heiheihei',
    age: 34,
    _password:'123'
}
user = new Proxy(user, {
    get (target, prop) {
        if (prop.startsWith('_')) { 
            throw new Error('不可访问')
        } else {
            return target[prop]
        }
    },
    set (target, prop, val) {
        if (prop.startsWith('_')) { 
            throw new Error('不可访问')
        } else {
            target[prop] = val
            return true
        }
    },
    // 拦截删除
    deleteProperty (target, prop) {
         if (prop.startsWith('_')) { 
            throw new Error('不可删除')
         } else {
             console.log(prop,target[prop],':prop');
            delete target[prop]
            return true
        }
    },
    ownKeys (target) {
        return Object.keys(target).filter(key => !key.startsWith('_'))
    },
    

})


console.log(user.age); //34
console.log(user._password) //3-12.js:124 Uncaught  Error: 不可访问
user._password = 'xx'

try {
    delete user._password
} catch (e) {
    console.log(e.message);
}
console.log(user._password,'====dddd');

for (let key in user) {
    console.log(key,':====key');
}
  • apply 拦截函数调用
let sum = (...args) => {
    let num = 0
    args.forEach(item => {
        num += item
    })
    return num
}

sum = new Proxy(sum, {
    apply (target,ctx,args) {
        return target(...args)*2
    }
})

// console.log(sum(1,2));// 6
// console.log(sum.call(null,1,2,3));// 12
console.log(sum.apply(null,[1,2,3]));// 12
  • construct 拦截new
let User = class {
    constructor(name) {
        this.name = name
    }
}

User = new Proxy(User, {
    constructor (target, args, newTarget) {
        return new target(...args)
    }
})

console.log(new User('imm'));

小结

拦截器作用
get拦截对象属性的读取,比如proxy.foo和proxy['foo']
set拦截对象属性的设置,返回一个布尔值,比如proxy.foo = v或proxy['foo'] = v
has拦截propKey in proxy的操作,返回一个布尔值
ownKeys拦截Object.getOwanPropertyNames(proxy)、Object.getOwanPeopertySymbols(proxy)、Object.keys(proxy)、for...in循环,返回一个数组
deleteProperty拦截delete proxy[propKey]的操作,返回一个布尔值
apply拦截函数的调用,call和apply操作
construct拦截new命令,返回一个对象

Reflect

  • 将Object属于语言内部的方法放到Reflect上

  • 修改某些Object方法的返回结果,让其变得更合理

  • 让Object操作变成函数行为

  • Reflect对象的方法与proxy对象的方法一一对应

  • 改造案例

try {
    Object.defineProperty()
} catch (e) { }

if (Reflect.defineProperty()) { // boolean
    
}

console.log('assign' in Object) //true
console.log(Reflect.has(Object, 'assign')) //true



let user = {
    userName: 'heiheihei',
    age: 34,
    _password:'123'
}
user = new Proxy(user, {
    get (target, prop) {
        if (prop.startsWith('_')) { 
            throw new Error('不可访问')
        } else {
            // return target[prop]
            return Reflect.get(target, prop)
        }
    },
    set (target, prop, val) {
        if (prop.startsWith('_')) { 
            throw new Error('不可访问')
        } else {
            // target[prop] = val
            Reflect.set(target,prop,val)
            return true
        }
    },
    // 拦截删除
    deleteProperty (target, prop) {
         if (prop.startsWith('_')) { 
            throw new Error('不可删除')
         } else {
            //  console.log(prop,target[prop],':prop');
            //  delete target[prop]
            Reflect.deleteProperty(target,prop)
            return true
        }
    },
    ownKeys (target) {
        // return Object.keys(target).filter(key => !key.startsWith('_'))
        return Reflect.ownkeys(target).filter(key => !key.startsWith('_'))
    },
    

})