一、Reflect

1、简介

Reflect提供拦截Javascript对象操作的方法,这些方法与处理器对象的方法相对应。Reflect不是一个函数对象,它是不能构造的,它的所有属性和方法都是静态的。

2、方法

Reflect对象提供的静态函数具有和处理器对象(handler)相同的方法名,其中一些方法与Object对应的方法相同。

  • Reflect.apply()

    Function.prototype.apply()类似

  • Reflect.construct()

    对构造函数进行new操作,相当于执行new target(...args)

  • Reflect.defineProperty()

    Object.defineProperty()类似

  • Reflect.deleteProperty()

    相当于执行delete target[name]

  • Reflect.get()

    获取对象的某个属性值,相当于执行target[name]

  • Reflect.set()

    给对象属性设置值的函数,返回Boolean类型值表示成功与否

  • Reflect.getOwnPropertyDescriptor()

    Object.getOwnPropertyDescriptor()类似

  • Reflect.getPrototypeOf()

    Object.getPrototypeOf()类似

  • Reflect.setPrototypeOf()

    Object.setPrototypeOf()类似

  • Reflect.has()

    判断一个对象是否存在某个属性,和in运算符功能相同

  • Reflect.isExtensible()

    Object.isExtensible()类似

  • Reflect.ownKeys()

    返回一个对象的所有自身属性(不包含继函属性)的数组

  • Reflect.preventExtensions()

    Object.preventExtensions()类似

二、Proxy

1、简介

Proxy对象通常用于给基本操作定义自定义行为,如:属性查找、赋值、枚举、函数调用等。

  • 语法
let p = new Proxy(target, handler);
  • 参数

    • target

      使用Proxy包装的(目标)对象,即需要代理的对象,可以是任何类型的对象,包括原生数组、函数或者是另一个代理对象。

    • handler

      使用handler定义一些代理函数,当执行代理proxy对象的操作时会先被handler的相应函数拦截。

2、Handler

Handler(处理器)对象用来自定义代理对象的各种可代理操作,一共有13种可代理操作:

1、apply

拦截函数的调用。要求代理的目标对象(target)必须是可被调用的,即它是一个函数对象。

  • 语法

      var p = new Proxy(target, {
          apply: function(target, thisArg, argumentsList){
    			
          }
      });
    
    • target

      目标对象(函数)

    • thisArg

      被调用时的上下文对象

    • argumentsList

      被调用时的参数数组

  • 样例

function sum(a, b){
	return a + b;
}
const handler = {
	apply(target, thisArg, args){
		console.log(args);
		return target(args[0], args[1]) * 10;
	}
};
let proxy = new Proxy(sum, handler);
console.log(sum(1, 2));
console.log('------');
console.log(proxy(1, 2));

2、construct

拦截new操作符。要求代理的目标对象(target)必须具有Construct内部方法(即new target必须是有效的)且必须返回一个对象。

  • 语法

      var p = new Proxy(target, {
          construct: function(target, argumentList, newTarget){
    			
          }
      });
    
    • target

      目标对象

    • argumentList

      构造函数(constrcutor)的参数列表

    • newTarget

      最初被调用的构造函数(即语法定义中的p,Proxy对象)

  • 样例

//怪物 - 性情
function monster(disposition){
	this.disposition = disposition;
}
const handler = {
	construct(target, args, newTarget){
		console.log('call monster constructor');
		return new target(...args);
	}
};
let proxy = new Proxy(monster, handler);
//fierce: 凶猛的
console.log(new proxy('fierce').disposition);

输出:

call monster constructor
fierce
3、defineProperty

拦截对象的defineProperty(Object.defineProperty()Reflect.defineProperty())操作。此方法必须返回Boolean类型值,表示定义属性是否成功。

  • 语法

      var p = new Proxy(target, {
          defineProperty: function(target, property, descriptor){
    			
          }
      });
    
    • target

      目标对象

    • property

      要定义或修改的属性名

    • descriptor

      将被定义或修改的属性描述符

  • 样例

let target = {};
let p = new Proxy(target, {
	defineProperty(target, prop, descriptor){
		console.log(prop, descriptor);
		return Reflect.defineProperty(target, prop, descriptor);
	}
});
let desc = {
	configurable: true, 
	enumerable: true,
	value: 10
};
Object.defineProperty(p, 'a', desc);//a {value: 10, enumerable: true, configurable: true}
console.log(p.a, target.a);//10 10
4、deleteProperty

拦截对象删除属性的操作(delete obj.foo),返回Boolean类型值,表示属性是否删除成功。

  • 语法

      var p = new Proxy(target, {
          deleteProperty: function(target, property){
    			
          }
      });
    
    • target

      目标对象

    • property

      要删除的属性名

  • 样例

let target = {name: 'albert'};
let p = new Proxy(target, {
	deleteProperty(target, prop){
		console.log(`delete property: ${prop}`);
		return Reflect.deleteProperty(target, prop);
	}
});
console.log(p.name);
delete p.name;
console.log(p.name, target.name);
5、get

拦截读取对象属性的操作(proxy.foo)。

  • 语法

      var p = new Proxy(target, {
          get: function(target, property, receiver){
    		
          }
      });
    
    • target

      目标对象

    • property

      要获取的属性名

    • receiver

      Proxy或继承Proxy的对象

  • 样例

let target = {name: 'albert'};
let p = new Proxy(target, {
	get(target, prop, receiver){
		console.log(`get ${prop} value:`);
		return Reflect.get(target, prop, receiver);
	}
});
p.name;

输出:

get name value:
albert
6、set

拦截设置对象属性的操作(proxy.foo = bar),返回Boolean类型值,表示设置属性是否成功。

  • 语法

      var p = new Proxy(target, {
          set: function(target, property, value, receiver){
    			
          }
      });
    
    • property

      要设置值的属性名称

    • value

      要设置的值

  • 样例

let target = {};
let p = new Proxy(target, {
	set(target, property, value, receiver){
		console.log(`set property ${property} = ${value}`);
		return Reflect.set(target, property, value, receiver);
	}
});
p.name = 'albert';
console.log(target.name, p.name);

输出:

set property name = albert
albert albert
7、getOwnPropertyDescriptor

拦截对象获取自身属性描述的对象,此方法必须返回Objectundefined

  • 语法

      var p = new Proxy(target, {
          getOwnPropertyDescriptor(target, prop){
    		
          }
      });
    
    • target

      目标对象

    • prop

      需要获取属性描述的属性名

  • 样例

let target = {name: 'albert'};
let p = new Proxy(target, {
	getOwnPropertyDescriptor(target, prop){
		console.log(`get ${prop} descriptor`);
		return {
			configurable: true, enumerable: true, value: 'Tom'
		};
	}
});
let desc = Object.getOwnPropertyDescriptor(p, 'name');
console.log(desc.value);

输出:

get name descriptor
Tom
8、getPrototypeOf

拦截获取对象原型的操作,该方法必须返回对象或null

  • 语法

      var p = new Proxy(obj, {
          getPrototypeOf: function(target){
    		
          }
      });
    
  • 样例

let proto = {};
let obj = {name: 'albert'};
let handler = {
	getPrototypeOf(target){
		console.log(target === obj);//true
		console.log(this === handler);//true
		return proto;
	}
};
let p = new Proxy(obj, handler);
console.log(Object.getPrototypeOf(p) === proto);//true
9、setPrototypeOf

拦截设置对象原型的操作,必须返回Boolean类型值,表示是否设置成功。

  • 语法

      var p = new Proxy(target, {
          setPrototypeOf: function(target, prototype){
    			
          }
      });
    
    • prototype

      对象新原型或null

  • 样例

let target = {name: 'ablert'};
let newProto = {name: 'Tom', age: 3};
let p = new Proxy(target, {
	setPrototypeOf(target, prototype){
		console.log(`set prototype`);
		return Reflect.setPrototypeOf(target, prototype);
	}
});
Object.setPrototypeOf(p, newProto);
console.log(target.name, target.age);//ablert 3
console.log(p.name, p.age);//ablert 3
10、has

拦截查询对象属性的操作,必须返回Boolean类型值,表示对象是否拥有该属性。

  • 语法

      var p = new Proxy(target, {
          has: function(target, prop){
    			
          }
      });
    
  • 样例

let target = {name: 'Tom', age: 3};
let p = new Proxy(target, {
	has(target, prop){
		return Reflect.has(target, prop);
	}
});
console.log('name' in p);//true
console.log('sex' in p);//false
11、isExtensible

拦截判断对象是否可扩展的操作,返回Boolean值。

  • 语法

      var p = new Proxy(target, {
          isExtensible: function(target){
    		
          }
      });
    
  • 样例

let p = new Proxy({}, {
	isExtensible(target){
		console.log('isExtensible called');
		return 1;
	}
});
console.log(Object.isExtensible(p));//true
12、ownKeys

拦截获取对象自身所有属性的操作。

  • 语法

      var p = new Proxy(target, {
          ownKeys: function(target){
    		
          }
      });
    
  • 样例

let target = {age: 5};
let p = new Proxy(target, {
	ownKeys(target){
		console.log('ownKeys called');
		return ['a', 'b', 'c'];
	}
});
console.log(Object.getOwnPropertyNames(p));//["a", "b", "c"]
13、preventExtensions

拦截将对象变为不可扩展的操作,返回已经不可扩展的对象。

  • 语法

      var p = new Proxy(target, {
          preventExtensions: function(target){
    		
          }
      });
    
  • 样例

let target = {age: 5};
let p = new Proxy(target, {
	preventExtensions(target){
		console.log('preventExtensions');
		return Reflect.preventExtensions(target);
	}
});
Object.preventExtensions(p);
console.log(Object.isExtensible(target));//false
console.log(Object.isExtensible(p));//false
附: