在学习ES6中反射和代理之前,先要明白属性描述符和存储器属性的原理,然后理解反射和代理的原理就会非常的简单。
在ES5之前,JavaScript语言本身并没有提供可以直接检测属性特性的方法,比如判断属性是否可读,ES5 增加了属性描述符,可以更细腻的控制属性的不同操作。
Object.getOwnPropertyDescriptor()方法可以查看描述属性的相关信息, 第一个参数为对象,第二个参数为对象的属性值。
let obj={
a:1,
b:2
}
// Object.getOwnPropertyDescriptor()方法可以查看描述属性的相关信息,
// 第一个参数为对象,第二个参数为对象的属性值。
console.log(Object.getOwnPropertyDescriptor(obj,"a"));
configurable:true 该属性是否被属性描述符修改
enumerable:true 该属性是否可以被枚举
value:1 属性值
writable:true 该属性是否可以被重新赋值
Object.getOwnPropertyDescriptors()方法可以查看该对象全部属性的描述属性的相关信息, 只有一个参数为对象,查看该对象全部属性的描述属性的相关信息。
let obj={
a:1,
b:2
}
console.log(Object.getOwnPropertyDescriptors(obj));
Object.defineProperty()属性修饰符可以修改对象中的属性的相关描述信息,第一个参数为对象,第二个参数为对象中的属性值
let obj = {
a: 1,
b: 2
}
// configurable:true 该属性是否被属性描述符修改
// enumerable:true 该属性是否可以被枚举
// value:1 属性值
// writable:true 该属性是否可以被重新赋值
Object.defineProperty(obj, "a", {
configurable: true,
enumerable: true,
enumerable: true,
value: 10
});
console.log(obj); //obj.a的值改成了10
Object.definePropertys()属性修饰符可以修改对象中的全部属性的相关描述信息, 第一个参数为对象,可以修改对象中的全部属性的相关描述信息
let obj = {
a: 1,
b: 2
}
Object.defineProperties(obj, {
a: {
configurable: true,
enumerable: true,
enumerable: true,
value: 10
},
b: {
configurable: true,
enumerable: true,
enumerable: true,
value: 10
}
});
存储器属性: 在控制台的表现形式为(…)
在属性描述符中, 如果配置了get和set任意一个, 则该属性不再是普通属性, 而是存储器属性,set() get() 函数, 如果一个属性为存储器属性, 再获取该属性时, 会运行get方法, 将get方法得到的 返回值作为属性值, 如果给该属性赋值, 则会运行set方法。
let obj = {
a: 1,
b: 2
}
Object.defineProperty(obj, "a", {
get() {
return _a;
},
set(val) {
return _a = val;
}
});
obj.a = 10;
console.log(obj.a);
在属性描述符中, 如果配置了get和set任意一个, 则该属性不再是普通属性, 而是存储器属性
let obj = {
a: 1,
b: 2
}
Object.defineProperties(obj, {
a: {
get() {
return _a;
},
set(val) {
return _a = val;
}
},
c: {
get() {
return _c;
},
set(val) {
return _c = val;
}
}
});
obj.c = 10;
console.log(obj.c);
Reflect(反射)是ES6为更方便的操作对象而提供的新API 。
Reflect是js的内置对象,它提供了一系列的方法,可以让开发者通过调用这些方法,访问一些js底层功能
属性的取值,赋值,普通函数和构造函数的调用,判断对象的属性,删除对象的属性。。。。。
Reflect可以实现底层功能
有一个重要理念,在ES5被提供出:减少代码,让代码更加纯粹这种理念很大程度上受函数式编程思想的影响
ES6进一步贯彻落实这个理念,他认为,对属性内存的控制、原型链的修改,函数的调用等,这些都属于底层实现,
属于一种语法,因此希望提出来,形成一个正常的API,并高度聚集到一个对象中去,于是就形成了Reflest对象
5.1Reflect.set()给对象的属性赋值
let obj = {
a: 1,
b: 2
}
// Reflect.set()方法第一个参数为对象,第二个参数为对象的属性,第三个参数为对象的属性值
// 如果对象中存在该属性的话,就会修改属性值,如果不存在的话,就会为对象添加一个属性
Reflect.set(obj, "c", 3);
console.log(obj); //{a: 1, b: 2, c: 3}
Reflect.set()方法第一个参数为对象,第二个参数为对象的属性,第三个参数为对象的属性值,如果对象中存在该属性的话,就会修改属性值,如果不存在的话,就会为对象添加一个属性
5.2Reflect.get()读取对象的属性值
let obj = {
a: 1,
b: 2
}
console.log(Reflect.get(obj, "a"));
5.3Reflect.apply()
调用函数,并绑定this和参数列表,等同于函数调用
function func(a, b) {
console.log(this)
return a + b
}
// func(3,4)
console.log(Reflect.apply(func, null, [3, 4]))
5.4.Reflect.defineProperty()
类似于Object.defineProperty,区别在于Reflect如果配置出现问题,返回false而不是报错, 第一个参数为对象,第二个参数为对象中的属性值,可以用来修改对象的属性值和描述信息
let obj = {
a: 1,
b: 2
}
Reflect.defineProperty(obj, "a", {
value: 10,
configurable: false,
enumerable: false,
writable: false
});
console.log(obj);
5.5Reflect.deleteProperty()
Reflect.deleteProperty()方法,用来删除对象中的属性值
Reflect.deleteProperty(obj, "a")
console.log(obj)
5.6.Reflect.construct()
Reflect.construct()使用构造函数的方式创建对象
function Text(name, sex) {
this.name = name;
this.sex = sex;
}
const t = Reflect.construct(Text, [5, 6]);
console.log(t); //Text {name: 5, sex: 6}
5.7Reflect.has()
Reflect.has()方法判断一个对象是否拥有一个属性
console.log('b' in obj)
console.log(Reflect.has(obj, "a"))
以上都是Reflect的常用方法,详情方法大全可以在该网址学习:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect
代理:提供了修改底层实现的方式
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。
let p = new Proxy(target, handler);
target目标对象 (需要代理的对象)
handler 是一个普通对象,重写底层方法的对象
const obj = {
a: 1,
b: 2
}
const pro = new Proxy(obj, {
set(target, protertyKey, value) {
console.log(`对对象${
target}设置了${
protertyKey}属性的值${
value}`)
Reflect.set(target, protertyKey, value)
},
get(target, protertyKey) {
console.log(`对对象${
target}设置了${
protertyKey}属性的值`)
return Reflect.get(target, protertyKey);
},
has(target, protertyKey) {
return Reflect.has(target, protertyKey)
},
delete(target, protertyKey) {
return Reflect.delete(target, protertyKey);
}
});
console.log(pro);
Proxy 可以对目标对象的读取、函数调用等操作进行拦截,然后进行操作处理。它不直接操作对象,而是像代理模式,通过对象的代理对象进行操作,在进行这些操作时,可以添加一些需要的额外操作。
用代理对象创建一个观察者模式:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="container"></div>
<script>
// 创建一个观察者
function observer(target){
const div = document.getElementById("container")
const proxy = new Proxy(target,{
set(target,prop,value){
Reflect.set(target,prop,value)
render()
},
get(target,prop){
return Reflect.get(target,prop)
}
})
render()
function render(){
let html = "";
for(const prop of Object.keys(proxy)){
html += `
${
prop}
${
proxy[prop]}
`
}
div.innerHTML = html;
}
return proxy;
}
const target = {
a : 1,
b : 2
}
const obj = observer(target)
</script>
</body>
</html>