ECMAScript6_Day2

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/weixin_44289860/article/details/98730147

es6

1.Reflect & Proxy

Proxy 与 Reflect 是ES6 为了引入操作对象引入的API

Proxy 可以对目标对象的读取、函数调用等操作进行拦截,然后进行操作处理。它不直接操作对象,而是像代理模式。

Reflect 可以用于获取目标对象的行为,它与 Object 类似,但是更易读,为操作对象提供了一种更优雅的方式。它的方法与 Proxy 是对应的。

Proxy

Proxy对象由两个部分组成:target是目标对象、handler是一个对象,声明了代理target的指定行为。

    let target = {
        name: 'Tom',
        age: 24
    }
    
    let handler = {
    //  使用get来获取 target 的值
        get: function(target, key) {
            
            return target[key];
        },
     // 使用set来设置 target 的值
        set: function(target, key, value) {
           
            target[key] = value;
        }
    }
    
    //声明一个 Proxy 类型的对象
    let proxy = new Proxy(target, handler)

    proxy.name = 'AAA'
    console.log(proxy.name)     // 实际执行 handler.get
    proxy.age = 25 // 实际执行 handler.set


	//如果声明 target 为空对象
	// 则可以直接使用创建的Proxy 对象来添加 target 属性
	
		let targetEpt = {}
		let proxyEpt = new Proxy(targetEpt, handler)
		
		// 给 target 添加 name 属性并且 key 值为 'Tom'
		proxyEpt.name = 'Tom'
		
		targetEpt)


	//header 对象为空直接方位对象不进行设置拦截
		let targetEmpty = {}
		
		let proxyEmpty = new Proxy(targetEmpty,{})
		
		proxyEmpty.name = "Tom"
		
		targetEmpty) 
		
get方法:
				get(target,propKey,receiver)
	
	
set方法:	
				set(target, propKey, value, receiver)
	
	//用于拦截 target 对象上的 propKey 的赋值操作,给set方法加上判断,如果不符合条件将不会执行set方法
	let validator = {
    set: function(obj, prop, value) {
        if (prop === 'age') {
            if (!Number.isInteger(value)) {
                throw new TypeError('The age is not an integer');
            }
            if (value > 200) {
                throw new RangeError('The age seems invalid');
            }
        }
        // 对于满足条件的 age 属性以及其他属性,直接保存
        obj[prop] = value;
    }
};
	let proxy= new Proxy({}, validator)
	proxy.age = 100;
	proxy.age           // 100
	proxy.age = 'oppps' // 报错
	proxy.age = 300     // 报错

 receiver 表示原始操作行为所在对象,一般是 Proxy 实例本身。

apply(target , ctx , args)	
					用于拦截函数的掉调用、call和reply操作。target表示目标对象,ctx表示上下文,
			args表示目标对象的参数数组

has(target, propKey)
						用于拦截 HasProperty 操作,即在判断 target 对象是否存在 propKey 属性时
					会被这个方法拦截。此方法不判断一个属性是对象自身的属性,还是继承的属性。
							
construct(target, args)	
						用于拦截 new 命令。返回值必须为对象

deleteProperty(target, propKey)
							用于拦截 delete 操作,如果这个方法抛出错误或者返回 false ,propKey 
						属性就无法被 delete 命令删除。
						
defineProperty(target, propKey, propDesc)
							用于拦截 Object.definePro若目标对象不可扩展,增加目标对象上不存在的
						属性会报错若属性不可写或不可配置,则不能改变这些属性。

getOwnPropertyDescriptor(target, propKey)
							用于拦截 Object.getOwnPropertyD() 返回值为属性描述对象或者 
						undefined 。

getPrototypeOf(target)
							主要用于拦截获取对象原型的操作返回值必须是对象或者 null ,
					否则报错。另外,如果目标对象不可扩展(non-extensible),
					getPrototypeOf 方法必须返回目标对象的原型对象。

sExtensible(target)
					用于拦截 Object.isExtensible 操作。
				该方法只能返回布尔值,否则返回值会被自动转为布尔值。
				它的返回值必须与目标对象的isExtensible属性保持一致,否则会抛出错误。

ownKeys(target)
			用于拦截对象自身属性的读取操作。主要包括以下操作:
		方法返回的数组成员,只能是字符串或 Symbol 值,否则会报错。
		若目标对象中含有不可配置的属性,则必须将这些属性在结果中返回,否则就会报错。
		若目标对象不可扩展,则必须全部返回且只能返回目标对象包含的所有属性,不能包含不存在的属性,
		否则也会报错。


preventExtensions(target)
				拦截 Object.preventExtensions 操作。
			该方法必须返回一个布尔值,否则会自动转为布尔值。

etPrototypeOf
			主要用来拦截 Object.setPrototypeOf 方法。
		返回值必须为布尔值,否则会被自动转为布尔值。
		若目标对象不可扩展,setPrototypeOf 方法不得改变目标对象的原型。

Proxy.revocable()
		用于返回一个可取消的 Proxy 实例。

Reflect

es6中未来的新方法只会部署在Reflect对象上

 	静态方法:
 			Reflect.get(target, name, receiver)
	
let exam = {
    name: "Tom",
    age: 24,
    get info(){
        return this.name + this.age;
    }
}
Reflect.get(exam, 'name'); // "Tom"
 
// 当 target 对象中存在 name 属性的 getter 方法, getter 方法的 this 会绑定 // receiver
let receiver = {
    name: "Jerry",
    age: 20
}
Reflect.get(exam, 'info', receiver); // Jerry20
 
// 当 name 为不存在于 target 对象的属性时,返回 undefined
Reflect.get(exam, 'birth'); // undefined
 
// 当 target 不是对象时,会报错
Reflect.get(1, 'name'); // TypeError



Reflect.set(target, name, value, receiver)

将 target 的 name 属性设置为 value。返回值为 boolean ,true 表示修改成功,false 表示失败。
当 target 为不存在的对象时,会报错。


let exam = {
    name: "Tom",
    age: 24,
    set info(value){
        return this.age = value;
    }
}
exam.age; // 24
Reflect.set(exam, 'age', 25); // true
exam.age; // 25
 
// value 为空时会将 name 属性清除
Reflect.set(exam, 'age', ); // true
exam.age; // undefined
 
// 当 target 对象中存在 name 属性 setter 方法时,setter 方法中的 this 会绑定 // receiver , 所以修改的实际上是 receiver 的属性,
let receiver = {
    age: 18
}
Reflect.set(exam, 'info', 1, receiver); // true
receiver.age; // 1
 
let receiver1 = {
    name: 'oppps'
}
Reflect.set(exam, 'info', 1, receiver1);
receiver1.age; // 1


Reflect.has(obj, name)	
		是 name in obj 指令的函数化,用于查找 name 属性在 obj 对象中是否存在。
	返回值为 boolean。如果 obj 不是对象则会报错 TypeError。

Reflect.deleteProperty(obj, property)
			是 delete obj[property] 的函数化,用于删除 obj 对象的 property 属性,返回值为 
		boolean。如果 obj 不是对象则会报错 TypeError。
	
Reflect.construct(obj, args)
		等同于 new target(...args)。

Reflect.getPrototypeOf(obj)
			用于读取 obj 的 _proto_ 属性。在 obj 不是对象时不会像 Object 一样把 obj 转为对象,
		而是会报错。

Reflect.setPrototypeOf(obj, newProto)
			用于设置目标对象的 prototype。
			
Reflect.apply(func, thisArg, args)
	等同于 Function.prototype.apply.call(func, thisArg, args) 。func 表示目标函数;thisArg 表示目标函数绑定的 this 对象;args 表示目标函数调用时传入的参数列表,可以是数组或类似数组的对象。若目标函数无法调用,会抛出 TypeError 。

Reflect.defineProperty(target, propertyKey, attributes)
	用于为目标对象定义属性。如果 target 不是对象,会抛出错误。

Reflect.getOwnPropertyDescriptor(target, propertyKey)
		用于得到 target 对象的 propertyKey 属性的描述对象。在 target 不是对象时,
	会抛出错误表示参数非法,不会将非对象转换为对象。

Reflect.isExtensible(target)
		用于判断 target 对象是否可扩展。返回值为 boolean 。如果 target 参数不是对象,会抛出错误。

Reflect.preventExtensions(target)
		用于让 target 对象变为不可扩展。如果 target 参数不是对象,会抛出错误。

Reflect.ownKeys(target)
		用于返回 target 对象的所有属性,等同于 Object.getOwnPropertyNames 
	与Object.getOwnPropertySymbols 之和。

组合使用

Reflect 对象的方法与 Proxy 对象的方法是一一对应的。
所以 Proxy 对象的方法可以通过调用 Reflect 对象的方法获取默认行为,然后进行额外操作。

let exam = {
    name: "Tom",
    age: 24
}
let handler = {
    get: function(target, key){
        console.log("getting "+key);
        return Reflect.get(target,key);
    },
    set: function(target, key, value){
        console.log("setting "+key+" to "+value)
        Reflect.set(target, key, value);
    }
}
let proxy = new Proxy(exam, handler)
proxy.name = "Jerry"
proxy.name

使用场景拓展
实现观察者模式

// 定义 Set 集合
const queuedObservers = new Set();
// 把观察者函数都放入 Set 集合中
const observe = fn => queuedObservers.add(fn);
// observable 返回原始对象的代理,拦截赋值操作
const observable = obj => new Proxy(obj, {set});
function set(target, key, value, receiver) {
  // 获取对象的赋值操作
  const result = Reflect.set(target, key, value, receiver);
  // 执行所有观察者
  queuedObservers.forEach(observer => observer());
  // 执行赋值操作
  return result;
}

本文摘抄 & 总结自 菜鸟教程

猜你喜欢

转载自blog.csdn.net/weixin_44289860/article/details/98730147