js基础复习(四)

386 阅读2分钟

1.Reflect

反射机制是指编译阶段不知道哪个类被加载,而是在运行阶段的时候才加载,执行。

1.1 Reflect.apply

传统做法

console.log(Math.floor.apply(null, [1.13])) // 1

Reflect

Reflect.apply(Math.floor, null, [1.73])  // 1

类似可以把很多方法都这么使用,比如Math.max等等

使用场景

let price = 101
Reflect.apply(price > 100 ? Math.floor : Math.ceil, null, [price])

ES5

let price = 101
if (price > 100) {
    Math.floor.apply(null, [price])
} else {
    Math.ceil.apply(null, [price])
}

1.2 Reflect.construct

function Person(name) {
  this.name = name;
}

// new写法
let person = new Person('jack')
// Reflect
let nPerson = Reflect.construct(Person, ['jack'])
let d = Reflect.construct(Date, [])
console.log(d.getTime())

1.3 Reflect.defineProperty

Object.defineProperty 返回对象

let student = {}
console.log(Object.defineProperty(student, 'name', { value: 'Mike' })) // {name: "Mike"}

Reflect.defineProperty 返回true或false

let student = {}
console.log(Reflect.defineProperty(student, 'name', { value: 'Mike' })) // true

1.4 Reflect.deleteProperty

let student = {
    name: 'jack',
    age: 12
}
console.log(Reflect.deleteProperty(student, 'name')) // true

1.5 Reflect.isExtensible

Reflect.isExtensible (target) 对应Object.isExtensible,返回一个布尔值,表示当前对象是否可扩展

const object1 = {};

console.log(Reflect.isExtensible(object1));
// expected output: true

Reflect.preventExtensions(object1);

console.log(Reflect.isExtensible(object1));
// expected output: false

const object2 = Object.seal({}); // 或者 Object.freeze() freeze不可修改属性 seal可修改密封属性

console.log(Reflect.isExtensible(object2));
// expected output: false

1.6 Reflect.getOwnPropertyDescriptor 获取属性描述符

Reflect.getOwnPropertyDescriptor({x: "hello"}, "x");
// {value: "hello", writable: true, enumerable: true, configurable: true}

Reflect.getOwnPropertyDescriptor({x: "hello"}, "y");
// undefined

Reflect.getOwnPropertyDescriptor([], "length");
// {value: 0, writable: true, enumerable: false, configurable: false}

1.7 Reflect.ownKeys

Reflect.ownKeys(obj) // ["x", "y"]
Reflect.ownKeys([]) // ["length"]
Reflect.ownKeys([1, 2, 3]) // ["0", "1", "2", "length"] 索引加length

1.8 Reflect.setPrototypeOf Reflect.getPrototypeOf

可以修改和获取目标的原型

let arr = []
Reflect.getPrototypeOf(arr)
Reflect.setPrototypeOf(arr, String.prototype) // 改成了字符串的原型
Reflect.getPrototypeOf(arr)

2. Proxy

2.1 使用方法

let o = {
	name: '张三',
	money: 190
}

let d = new Proxy(o, {
    get (target, key) {
	    if (key === 'money') {
			return target[key] + 20
		} else {
            return target[key]
		}
    }
})

console.log(d.money) // 210

2.2 使用场景

2.2.1 使对象变为只读

ES5

let o = {
    x: 1,
    y: 2
}

for (let [key] of Object.entries(o)) {
    Object.defineProperty(o, key, {
        writable: false
    })
} 

ES6 proxy

let o = {
    x: 1,
    y: 2
}

let d = new Proxy(o, {
    get (target, key) {
        return target[key]
    },
    
    set (target, key, value) {
        return false
    }
})

好处是不改变原对象,原对象仍然是可操作的

2.2.2 拦截无效操作

let o = {
    x: 1,
    y: 2
}

let validator = (target, key, value) => {
    if (Reflect.has(target, key)) {
        if (key === 'x') {
            if (value > 300) { // x大于300就不能赋值
                return false
            } else {
            target[key] = value
        }
        } else {
            target[key] = value
        }
    } else {
        return false
    }
}

let d = new Proxy(o, {
    get (target, key) {
        return target[key]
    },
    
    set: validator
})

2.2.3 上报违规操作

window.addEventListener('error', (e) => {
    // 不满足就触发上报异常机制
    console.log(e)
}, true)

let o = {
    x: 1,
    y: 2
}

let validator = (target, key, value) => {
    if (Reflect.has(target, key)) {
        if (key === 'x') {
            if (value > 300) {
                throw new TypeError('x exceed 300') // 抛出异常
            } else {
            target[key] = value
        }
        } else {
            target[key] = value
        }
    } else {
        return false
    }
}

let d = new Proxy(o, {
    get (target, key) {
        return target[key]
    },
    
    set: validator
})

2.2.4 生成一个组件 每个id不同且只读

class Component {
    constructor () {
        this.proxy = new Proxy({
            id: Math.random().toString(16).slice(-8)
        }, {})
    }
    
    get id () {
        return this.proxy.id
    }
}

let com = new Component()
let com2 = new Component()

for (let i = 0; i < 10; i++) {
    console.log(com.id, com2.id)
}

2.3 撤销代理

let o = {
    x: 1,
    y: 2
}

let d = Proxy.revocable(o, {
    get (target, key) {
        return target[key]
    }
})

// d不是单纯的代理数据,要通过proxy获取信息
console.log(d.proxy)

d.revoke() // 代理对象已经被撤销