Proxy:用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等),用代理实例不影响原对象操作,实现代理拦截需要在代理对象上操作;
Reflect:一个内置的对象,它提供拦截 JavaScript 操作的方法。这些方法与 proxy handlers
的方法相同。Reflect不是一个函数对象,因此它是不可构造的。
注意:通过对目标对象创建代理,并在代理中进行对象操作进行拦截和自定义,可理解为达到了一种“元编程”(meta programming)的效果。
术语定义:
handler:包含捕捉器(trap)的占位符对象,可译为处理器对象。
traps:提供属性访问的方法。这类似于操作系统中捕获器的概念。
target:被 Proxy 代理虚拟化的对象。它常被作为代理的存储后端。根据目标验证关于对象不可扩展性或不可配置属性的不变量(保持不变的语义)。
简单举例:当对象中不存在属性名时,通过代理访问该属性,默认返回值为 nothing。设置属性被拦截后在里面写入属性设置也可以设置属性。
const handler = {
get: function(target, property) {
return property in target ? target[property] : 'nothing';
},
set: function(target, property, value, receiver) {
// target[property] = value;
Reflect.set(target, property, value);
console.log('Successfully set '+ property + ' to value ' + value + ".")
return true;
}
};
const p = new Proxy({}, handler);
p.a = 1; //Successfully set a to value 1.
console.log(p.a); // 1
console.log('b' in p, p.b); // false, 'nothing'
const p = new Proxy(target, handler)
语义:创建一个指向 target 对象的代理p,并传入执行各种操作时代理 p 的行为集合 handler。
名称 | 定义 |
---|---|
target | 要使用 Proxy 的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理) |
handler | 一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为 |
handler 对象的方法
handler 对象是一个容纳一批特定属性的占位符对象。它包含有 Proxy 的各个捕获器(trap)。所有的捕捉器是可选的。如果没有定义某个捕捉器,那么就会保留源对象的默认行为。
名称 | 定义 |
---|---|
handler.apply() | 函数调用操作的捕捉器 |
handler.construct() | new 操作符的捕捉器 |
handler.defineProperty() | Object.defineProperty 方法的捕捉器 |
handler.deleteProperty() | delete 操作符的捕捉器 |
handler.get() | 属性读取操作的捕捉器 |
handler.getOwnPropertyDescriptor() | Object.getOwnPropertyDescriptor 方法的捕捉器 |
handler.getPrototypeOf() | Object.getPrototypeOf 方法的捕捉器 |
handler.has() | in 操作符的捕捉器 |
handler.isExtensible() | Object.isExtensible 方法的捕捉器 |
handler.ownKeys() | Object.getOwnPropertyNames 方法和Object.getOwnPropertySymbols 方法的捕捉器 |
handler.preventExtensions() | Object.preventExtensions 方法的捕捉器 |
handler.set() | 属性设置操作的捕捉器 |
handler.setPrototypeOf() | Object.setPrototypeOf 方法的捕捉器 |
一些不标准的捕捉器已经被废弃并且移除了,链接。
定义:handler.apply() 方法用于拦截函数的调用,该方法会拦截目标对象的以下操作:proxy(...args)
、Function.prototype.apply()
和 Function.prototype.call()
、Reflect.apply()
。
语法:
var p = new Proxy(target, {
apply: function(target, thisArg, argumentsList) {
}
});
参数:参数传递给 apply 方法,this 上下文绑定在 handler 对象上。
target
目标对象(函数)、thisArg
被调用时的上下文对象、argumentsList
被调用时的参数数组。
返回值:任意值;
异常:target
必须是可被调用的一个函数对象,否则代理抛出错误 TypeError。
示例:演示捕获函数的调用
var p = new Proxy(function() {}, {
apply: function(target, thisArg, argumentsList) {
console.log('called: ' + argumentsList.join(', '));
return argumentsList[0] + argumentsList[1] + argumentsList[2];
}
});
console.log(p(1, 2, 3)); // "called: 1, 2, 3"
// 6
定义:handler.construct() 方法用于拦截 new 操作符。为了使 new 操作符在生成的 Proxy 对象上生效,用于初始化代理的目标对象自身必须具有 [[Construct]] 内部方法(即 new target 必须是有效的)。该拦截器可以拦截以下操作:new proxy(...args)
、Reflect.construct()
。
语法:
var p = new Proxy(target, {
construct: function(target, argumentsList, newTarget) {
}
});
参数:参数将会传递给 construct 方法,this 绑定在 handler 上。
target
目标对象(函数)、argumentsList
constructor 的参数列表、newTarget
最初被调用的构造函数,如语法示例中的p。
返回值:construct 方法必须返回一个对象;
异常:未返回一个对象则抛出错误 TypeError。
示例:演示拦截 new 操作
var p = new Proxy(function() {}, {
construct: function(target, argumentsList, newTarget) {
console.log('called: ' + argumentsList.join(', '));
// 如果此处return非对象则后面new操作异常,如return 1;
return { value: argumentsList[0] * 10 };
}
});
console.log(new p(1).value);
// "called: 1"
// 10
定义:handler.defineProperty() 用于拦截对对象的 Object.defineProperty()
操作。该方法会拦截目标对象的以下操作:Object.defineProperty()
、Reflect.defineProperty()
。
语法:
var p = new Proxy(target, {
defineProperty: function(target, property, descriptor) {
}
});
参数:参数将会被传递给 defineProperty 方法。this 绑定在 handler 对象上。
target
目标对象(函数)、property
待检索其描述的属性名、descriptor
待定义或修改的属性的描述符。
返回值:defineProperty 方法必须以一个 Boolean 返回,表示定义该属性的操作成功与否。
异常:不符合以下约束将抛出异常
示例:演示如何拦截对目标对象的 Object.defineProperty() 操作。
var p = new Proxy({}, {
defineProperty: function(target, prop, descriptor) {
console.log('called: ' + prop);
return true;
}
});
var desc = { configurable: true, enumerable: true, value: 10 };
Object.defineProperty(p, 'a', desc); // "called: a"
注意:当调用 Object.defineProperty() 或者 Reflect.defineProperty(),传递给 defineProperty 的 descriptor 有一个限制 - 只有以下属性才有用,非标准的属性将会被无视:enumerable
、configurable
、writable
、value
、get
、set
。
var p = new Proxy({}, {
defineProperty(target, prop, descriptor) {
console.log(descriptor);
return Reflect.defineProperty(target, prop, descriptor);
}
});
Object.defineProperty(p, 'name', {
value: 'proxy',
type: 'custom'
}); // { value: 'proxy' }
定义:handler.deleteProperty() 方法可以拦截 delete 操作。该方法会拦截以下操作:删除属性:delete proxy[foo]
和 delete proxy.foo
;Reflect.deleteProperty()
。
语法:
var p = new Proxy(target, {
deleteProperty: function(target, property) {
}
});
参数:deleteProperty 方法将会接受以下参数。this 被绑定在 handler 上。
target
目标对象(函数)、property
待删除的属性名。
返回值:deleteProperty 必须返回一个 Boolean 类型的值,表示了该属性是否被成功删除。
异常:如果目标对象的属性是不可配置的,那么该属性不能被删除。尝试删除则抛出错误 TypeError。
示例:演示对 delete 操作的拦截
var p = new Proxy({}, {
deleteProperty: function(target, prop) {
console.log('called: ' + prop);
return true;
}
});
delete p.a; // "called: a"
定义:handler.get() 方法用于拦截对象的读取属性操作。该拦截器可以拦截以下操作:访问属性:proxy[foo]
和 proxy.bar
;访问原型链上的属性:Object.create(proxy)[foo]
;Reflect.get()
。
语法:
var p = new Proxy(target, {
get: function(target, property, receiver) {
}
});
参数:参数将传递给 get 方法,this 上下文绑定在handler 对象上。
target
目标对象(函数)、property
被获取的属性名、receiver
Proxy 或者继承 Proxy 的对象。
返回值:任何值。
异常:不符合以下约束将抛出异常
示例:演示拦截属性值的读取操作
var p = new Proxy({}, {
get: function(target, prop, receiver) {
console.log("called: " + prop);
return 10;
}
});
console.log(p.a);
// "called: a"
// 10
异常
var obj = {};
Object.defineProperty(obj, "a", {
configurable: false,
enumerable: false,
value: 10,
writable: false
});
var p = new Proxy(obj, {
get: function(target, prop) {
return 20;
}
});
p.a; //会抛出 TypeError
定义:handler.getOwnPropertyDescriptor() 方法是 Object.getOwnPropertyDescriptor() 的钩子。该拦截器可以拦截以下操作:Object.getOwnPropertyDescriptor()
、Reflect.getOwnPropertyDescriptor()
语法:
var p = new Proxy(target, {
getOwnPropertyDescriptor: function(target, prop) {
}
});
参数:参数会被传入 getOwnPropertyDescriptor 方法中。这是绑定到 handler 上。
target
目标对象(函数)、prop
返回属性名称的描述。
返回值:getOwnPropertyDescriptor 方法必须返回一个 object 或 undefined。
异常:不符合以下约束将抛出异常
示例:
var p = new Proxy({ a: 20}, {
getOwnPropertyDescriptor: function(target, prop) {
console.log('called: ' + prop);
return { configurable: true, enumerable: true, value: 10 };
}
});
console.log(Object.getOwnPropertyDescriptor(p, 'a').value);
// "called: a"
// 10
异常
var obj = { a: 10 };
Object.preventExtensions(obj);
var p = new Proxy(obj, {
getOwnPropertyDescriptor: function(target, prop) {
return undefined;
}
});
Object.getOwnPropertyDescriptor(p, 'a'); // TypeError is thrown
定义:handler.getPrototypeOf() 是一个代理(Proxy)方法,当读取代理对象的原型时,该方法就会被调用。该拦截器可以拦截以下操作:Object.getPrototypeOf()
、Reflect.getPrototypeOf()
、__proto__
、Object.prototype.isPrototypeOf()
、instanceof
。
语法:
const p = new Proxy(obj, {
getPrototypeOf(target) {
...
}
});
参数:当 getPrototypeOf 方法被调用时,this 指向的是它所属的处理器对象。
target
被代理的目标对象。
返回值:getPrototypeOf 方法的返回值必须是一个对象或者 null。
异常:不符合以下约束将抛出异常
示例:
var obj = {};
var proto = {};
var handler = {
getPrototypeOf(target) {
console.log(target === obj); // true
console.log(this === handler); // true
return proto;
}
};
var p = new Proxy(obj, handler);
console.log(Object.getPrototypeOf(p) === proto); // true
5 种触发 getPrototypeOf 代理方法的方式
var obj = {};
var p = new Proxy(obj, {
getPrototypeOf(target) {
return Array.prototype;
}
});
console.log(
Object.getPrototypeOf(p) === Array.prototype, // true
Reflect.getPrototypeOf(p) === Array.prototype, // true
p.__proto__ === Array.prototype, // true
Array.prototype.isPrototypeOf(p), // true
p instanceof Array // true
);
异常
var obj = {};
var p = new Proxy(obj, {
getPrototypeOf(target) {
return "foo";
}
});
Object.getPrototypeOf(p); // TypeError: "foo" is not an object or null
var obj = Object.preventExtensions({});
var p = new Proxy(obj, {
getPrototypeOf(target) {
return {};
}
});
Object.getPrototypeOf(p); // TypeError: expected same prototype value
定义:handler.has() 方法是针对 in 操作符的代理方法。该拦截器可以拦截以下操作:属性查询:foo in proxy
;继承属性查询:foo in Object.create(proxy)
;with 检查: with(proxy) { (foo); }
;Reflect.has()
。
语法:
var p = new Proxy(target, {
construct: function(target, argumentsList, newTarget) {
}
});
参数:参数将会传递给 construct 方法,this 绑定在 handler 上。
target
目标对象、prop
需要检查是否存在的属性。
返回值:has 方法返回一个 boolean 属性的值。
异常:不符合以下约束将抛出异常
示例:演示拦截 in 操作符。
var p = new Proxy({}, {
has: function(target, prop) {
console.log('called: ' + prop);
return true;
}
});
console.log('a' in p);
// "called: a"
// true
异常
var obj = { a: 10 };
Object.preventExtensions(obj);
var p = new Proxy(obj, {
has: function(target, prop) {
return false;
}
});
'a' in p; // TypeError is thrown
定义:handler.isExtensible() 方法用于拦截对对象的 Object.isExtensible()。
该拦截器可以拦截以下操作:Object.isExtensible()
、Reflect.isExtensible()
。
语法:
var p = new Proxy(target, {
isExtensible: function(target) {
}
});
参数:参数将会被传递给 isExtensible方法。 this 绑定在 handler 对象上。
target
目标对象。
返回值:isExtensible方法必须返回一个 Boolean 值或可转换成 Boolean 的值。
异常:Object.isExtensible(proxy) 必须同 Object.isExtensible(target) 返回相同值,否则抛出错误 TypeError。
示例:演示Object.isExtensible()
var p = new Proxy({}, {
isExtensible: function(target) {
console.log('called');
return true; // 也可以 return 1; 等表示为 true 的值
}
});
console.log(Object.isExtensible(p));
// "called"
// true
异常
var p = new Proxy({}, {
isExtensible: function(target) {
return false; // return 0; return NaN 等都会报错
}
});
Object.isExtensible(p); // TypeError is thrown
定义:handler.ownKeys() 方法用于拦截 Reflect.ownKeys()。该拦截器可以拦截以下操作:Object.getOwnPropertyNames()
、Object.getOwnPropertySymbols()
、Object.keys()
;Reflect.ownKeys()
。
语法:
var p = new Proxy(target, {
ownKeys: function(target) {
}
});
参数:参数被传递给 ownKeys。this 被绑定在 handler 上。
target
目标对象。
返回值:ownKeys 方法必须返回一个可枚举对象。
异常:不满足以下约束将抛出异常
示例:演示拦截 Object.getOwnPropertyNames()
var p = new Proxy({}, {
ownKeys: function(target) {
console.log('called');
return ['a', 'b', 'c'];
}
});
console.log(Object.getOwnPropertyNames(p));
// "called"
// [ 'a', 'b', 'c' ]
定义:handler.preventExtensions() 方法用于设置对Object.preventExtensions()的拦截。该拦截器可以拦截以下操作:Object.preventExtensions()
、Reflect.preventExtensions()
。
语法:
var p = new Proxy(target, {
preventExtensions: function(target) {
}
});
参数:参数传递给 preventExtensions 方法。它会绑定到这个 handler。
target
所要拦截的目标对象。
返回值:preventExtensions 方法返回一个布尔值。
异常:如果目标对象是可扩展的,那么只能返回 false,否则异常。
示例:演示拦截Object.preventExtensions()
var p = new Proxy({}, {
preventExtensions: function(target) {
console.log('called');
Object.preventExtensions(target);
return true;
}
});
console.log(Object.preventExtensions(p));
// "called"
// false
异常
var p = new Proxy({}, {
preventExtensions: function(target) {
return true;
}
});
Object.preventExtensions(p); // 抛出类型错误
定义:handler.set() 方法是设置属性值操作的捕获器。该拦截器可以拦截以下操作:指定属性值:proxy[foo] = bar
和 proxy.foo = bar
;指定继承者的属性值:Object.create(proxy)[foo] = bar
;Reflect.set()
。
语法:
const p = new Proxy(target, {
set: function(target, property, value, receiver) {
}
});
参数:参数将会传递给 set() 方法。this 绑定在 handler 对象上。
target
目标对象、property
将被设置的属性名或 Symbol、value
新属性值、receiver
最初被调用的对象。通常是 proxy 本身,但 handler 的 set 方法也有可能在原型链上,或以其他方式被间接地调用(因此不一定是 proxy 本身)。
注:如果有一段代码执行 obj.name = “jen”, obj 不是一个 proxy,且自身不含 name 属性,但是它的原型链上有一个 proxy,那么,那个 proxy 的 set() 处理器会被调用,而此时,obj 会作为 receiver 参数传进来。
返回值:set() 方法应当返回一个布尔值,返回 true 代表属性设置成功;在严格模式下,如果 set() 方法返回 false,那么会抛出一个 TypeError 异常。
异常:不满足以下约束将抛出异常
示例:演示捕获属性的设置操作
var p = new Proxy({}, {
set: function(target, prop, value, receiver) {
target[prop] = value;
console.log('property set: ' + prop + ' = ' + value);
return true;
}
})
console.log('a' in p); // false
p.a = 10; // "property set: a = 10"
console.log('a' in p); // true
console.log(p.a); // 10
定义:handler.setPrototypeOf() 方法主要用来拦截 Object.setPrototypeOf()。该拦截器可以拦截以下操作:Object.setPrototypeOf()
、Reflect.setPrototypeOf()
。
语法:
var p = new Proxy(target, {
setPrototypeOf: function(target, prototype) {
}
});
参数:参数将会传递给 setPrototypeOf 方法。
target
被拦截目标对象、prototype
对象新原型或为null。
返回值:如果成功修改了[[Prototype]], setPrototypeOf 方法返回 true,否则返回 false。
异常:如果 target 不可扩展,原型参数必须与 Object.getPrototypeOf(target) 的值相同,否则异常。
示例:演示拦截 new 操作
var handlerReturnsFalse = {
setPrototypeOf(target, newProto) {
return Reflect.setPrototypeOf(target, newProto);
}
};
var newProto = {a:2},target = {};
var p1 = new Proxy(target, handlerReturnsFalse);
Object.setPrototypeOf(p1, newProto);
//target.__proto__
//{a: 2}
名称 | 定义 |
---|---|
Proxy.revocable() | 创建一个可撤销的Proxy对象,这个可撤销的Proxy对象是由Proxy对象和一个revoke撤销方法组成的,其结构为:{“proxy”: proxy, “revoke”: revoke} |
注意:{“proxy”: proxy, “revoke”: revoke}中: proxy
表示新生成的代理对象本身,和用一般方式 new Proxy(target, handler) 创建的代理对象没什么不同,只是它可以被撤销掉; revoke
为撤销方法,调用的时候不需要加任何参数,就可以撤销掉和它一起生成的那个代理对象。
Proxy.revocable()示例
var revocable = Proxy.revocable({}, {
get(target, name) {
return "[[" + name + "]]";
}
});
var proxy = revocable.proxy;
proxy.foo; // "[[foo]]"
revocable.revoke();
console.log(proxy.foo); // 抛出 TypeError
proxy.foo = 1 // 还是 TypeError
delete proxy.foo; // 又是 TypeError
typeof proxy // "object",因为 typeof 不属于可代理操作
Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。这些方法 与proxy handlers 的方法相同 。Reflect不是一个函数对象,它是不可构造的,所以不能通过new 运算符对其进行调用,或者将Reflect对象作为一个函数来调用。
名称 | 定义 |
---|---|
Reflect.apply(target, thisArgument, argumentsList) | 对一个函数进行调用操作,同时可以传入一个数组作为调用参数。和 Function.prototype.apply() 功能类似。 |
Reflect.construct(target, argumentsList[, newTarget]) | 对构造函数进行 new 操作,相当于执行 new target(…args)。 |
Reflect.defineProperty(target, propertyKey, attributes) | 和 Object.defineProperty() 类似。如果设置成功就会返回 true |
Reflect.deleteProperty(target, propertyKey) | 作为函数的delete操作符,相当于执行 delete target[name]。 |
Reflect.get(target, propertyKey[, receiver]) | 获取对象身上某个属性的值,类似于 target[name]。 |
Reflect.getOwnPropertyDescriptor(target, propertyKey) | 类似于 Object.getOwnPropertyDescriptor()。如果对象中存在该属性,则返回对应的属性描述符,否则返回 undefined。 |
Reflect.getPrototypeOf(target) | 与 Object.getPrototypeOf() 方法几乎是一样的。都是返回指定对象的原型(即内部的 [[Prototype]] 属性的值)。 |
Reflect.has(target, propertyKey) | 判断一个对象是否存在某个属性,和 in 运算符 的功能完全相同。 |
Reflect.isExtensible(target) | 与 Object.isExtensible() 方法相似,判断一个对象是否可扩展(即是否能够添加新的属性)。 |
Reflect.ownKeys(target) | 返回一个包含所有自身属性(不包含继承属性)的数组。(类似于 Object.keys(), 但不会受enumerable 影响)。 |
Reflect.preventExtensions(target) | 类似于 Object.preventExtensions()。返回一个Boolean。 |
Reflect.set(target, propertyKey, value[, receiver]) | 将值分配给属性的函数。返回一个Boolean,如果更新成功,则返回true。 |
Reflect.setPrototypeOf(target, prototype) | 设置对象原型的函数。返回一个 Boolean, 如果更新成功,则返回true。 |
示例
检测一个对象是否存在特定属性并为这个对象添加新属性
const person = {
name: 'Bob',
age: 20,
greeting: function() {
console.log(`Hello! My name is ${this.name}`);
}
}
Reflect.has(person, 'name');
// true
Reflect.has(person, 'haircut');
// false
Reflect.set(person, 'eyes', 'black');
person.eyes;
// 'black'
定义:静态方法 Reflect.apply() 通过指定的参数列表发起对目标 (target) 函数的调用。
语法:
Reflect.apply(target, thisArgument, argumentsList)
参数:target
目标函数、thisArgument
target 函数调用时绑定的 this 对象、argumentsList
target 函数调用时传入的实参列表,该参数应该是一个类数组的对象。
返回值:返回值是调用完带着指定参数和 this 值的给定的函数后返回的结果。
异常:如果 target 对象不可调用,抛出 TypeError。
示例:
Reflect.apply(Math.floor, undefined, [1.75]);
// 1;
Reflect.apply(String.fromCharCode, undefined, [104, 101, 108, 108, 111]);
// "hello"
Reflect.apply(RegExp.prototype.exec, /ab/, ["confabulation"]).index;
// 4
Reflect.apply("".charAt, "ponies", [3]);
// "i"
定义:Reflect.construct() 方法的行为有点像 new 操作符 构造函数 , 相当于运行 new target(…args)。Reflect.construct允许你使用可变的参数来调用构造函数 ,这和使用new 操作符搭配对象展开符调用一样。
语法:
Reflect.construct(target, argumentsList[, newTarget])
参数:target
被运行的目标构造函数、argumentsList
类数组,目标构造函数调用时的参数、newTarget
(可选)t作为新创建对象的原型对象的constructor属性, 参考 new.target 操作符,默认值为target。
返回值:以target(如果newTarget存在,则为newTarget)函数为构造函数,argumentList为其初始化参数的对象实例。
异常:如果 target 或者 newTarget 不是构造函数,抛出TypeError,异常。
示例:
var d = Reflect.construct(Date, [1996, 6, 6]);
d instanceof Date; // true
d.getFullYear(); // 1996
定义:静态方法 Reflect.defineProperty() 方法允许精确添加或修改对象上的属性,基本等同于 Object.defineProperty() 方法,唯一不同是返回 Boolean 值。
语法:
Reflect.defineProperty(target, propertyKey, attributes)
参数:target
目标函数、propertyKey
要定义或修改的属性的名称、attributes
要定义或修改的属性的描述。
返回值:Boolean 值指示了属性是否被成功定义。
异常:如果target不是 Object,抛出一个 TypeError。
示例:
let obj = {}
Reflect.defineProperty(obj, 'x', {value: 8}) // true
obj.x // 8
定义:静态方法 Reflect.deleteProperty() 允许用于删除属性。它很像 delete operator ,但它是一个函数。Reflect.deleteProperty 允许你删除一个对象上的属性。返回一个 Boolean 值表示该属性是否被成功删除。它几乎与非严格的 delete operator 相同。
语法:
Reflect.deleteProperty(target, propertyKey)
参数:target
删除属性的目标对象、propertyKey
需要删除的属性的名称。
返回值:Boolean 值表明该属性是否被成功删除。
异常:抛出一个 TypeError,如果target不是 Object。
示例:
var obj = { x: 1, y: 2 };
Reflect.deleteProperty(obj, "x"); // true
obj; // { y: 2 }
var arr = [1, 2, 3, 4, 5];
Reflect.deleteProperty(arr, "3"); // true
arr; // [1, 2, 3, , 5]
// 如果属性不存在,返回 true
Reflect.deleteProperty({}, "foo"); // true
// 如果属性不可配置,返回 false
Reflect.deleteProperty(Object.freeze({foo: 1}), "foo"); // false
定义:Reflect.get()方法与从 对象 (target[propertyKey]) 中读取属性类似,但它是通过一个函数执行来操作的。
语法:
Reflect.get(target, propertyKey[, receiver])
参数:target
需要取值的目标对象、propertyKey
需要获取的值的键值、receiver
如果target对象中指定了getter,receiver则为getter调用时的this值。
返回值:属性的值。
异常:如果目标值类型不是 Object,则抛出一个 TypeError。
示例:
// Object
var obj = { x: 1, y: 2 };
Reflect.get(obj, "x"); // 1
// Array
Reflect.get(["zero", "one"], 1); // "one"
// Proxy with a get handler
var x = {p: 1};
var obj = new Proxy(x, {
get(t, k, r) { return k + "bar"; }
});
Reflect.get(obj, "foo"); // "foobar"
定义:静态方法 Reflect.getOwnPropertyDescriptor() 与 Object.getOwnPropertyDescriptor() 方法相似,与Object.getOwnPropertyDescriptor() 的唯一不同在于如何处理非对象目标。如果在对象中存在,则返回给定的属性的属性描述符。否则返回 undefined。
语法:
Reflect.getOwnPropertyDescriptor(target, propertyKey)
参数:target
需要寻找属性的目标对象、propertyKey
获取自己的属性描述符的属性的名称。
返回值:如果属性存在于给定的目标对象中,则返回属性描述符;否则,返回 undefined。
异常:抛出一个 TypeError,如果目标不是 Object。
示例:
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}
与 Object.getOwnPropertyDescriptor() 的不同点
如果该方法的第一个参数不是一个对象(一个原始值),那么将造成 TypeError 错误。而对于 Object.getOwnPropertyDescriptor,非对象的第一个参数将被强制转换为一个对象处理。
Reflect.getOwnPropertyDescriptor("foo", 0);
// TypeError: "foo" is not non-null object
Object.getOwnPropertyDescriptor("foo", 0);
// { value: "f", writable: false, enumerable: true, configurable: false }
定义:静态方法 Reflect.getPrototypeOf() 与 Object.getPrototypeOf() 方法几乎是一样的。都是返回指定对象的原型(即内部的 [[Prototype]] 属性的值)。
语法:
Reflect.getPrototypeOf(target)
参数:target
获取原型的目标对象。
返回值:给定对象的原型。如果给定对象没有继承的属性,则返回 null。
异常:如果 target 不是 Object,抛出一个 TypeError 异常。
示例:
Reflect.getPrototypeOf({}); // Object.prototype
Reflect.getPrototypeOf(Object.prototype); // null
Reflect.getPrototypeOf(Object.create(null)); // null
与 Object.getPrototypeOf() 比较
// 如果参数为 Object,返回结果相同
Object.getPrototypeOf({}) // Object.prototype
Reflect.getPrototypeOf({}) // Object.prototype
// 在 ES5 规范下,对于非 Object,抛异常
Object.getPrototypeOf('foo') // Throws TypeError
Reflect.getPrototypeOf('foo') // Throws TypeError
// 在 ES2015 规范下,Reflect 抛异常,Object 强制转换非 Object
Object.getPrototypeOf('foo') // String.prototype
Reflect.getPrototypeOf('foo') // Throws TypeError
// 如果想要模拟 Object 在 ES2015 规范下的表现,需要强制类型转换
Reflect.getPrototypeOf(Object('foo')) // String.prototype
定义:静态方法 Reflect.has() 作用与 in 操作符 相同。
语法:
Reflect.has(target, propertyKey)
参数:target
目标对象、propertyKey
属性名,需要检查目标对象是否存在此属性。
返回值:一个 Boolean 类型的对象指示是否存在此属性。
异常:如果目标对象并非Object 类型,抛出TypeError。
示例:
Reflect.has({x: 0}, "x"); // true
Reflect.has({x: 0}, "y"); // false
// 如果该属性存在于原型链中,返回 true
Reflect.has({x: 0}, "toString");
// Proxy 对象的 .has() 句柄方法
obj = new Proxy({}, {
has(t, k) { return k.startsWith("door"); }
});
Reflect.has(obj, "doorbell"); // true
Reflect.has(obj, "dormitory"); // false
定义:静态方法 Reflect.isExtensible() 判断一个对象是否可扩展(即是否能够添加新的属性)。与它 Object.isExtensible() 方法相似,但有一些不同,详情可见 与 Object.isExtensible() 的不同点。
语法:
Reflect.isExtensible(target)
参数:target
检查是否可扩展的目标对象。
返回值:返回一个 Boolean 值表明该对象是否可扩展。
异常:抛出一个 TypeError,如果对象不是 Object。
示例:
// New objects are extensible.
var empty = {};
Reflect.isExtensible(empty); // === true
// ...but that can be changed.
Reflect.preventExtensions(empty);
Reflect.isExtensible(empty); // === false
// Sealed objects are by definition non-extensible.
var sealed = Object.seal({});
Reflect.isExtensible(sealed); // === false
// Frozen objects are also by definition non-extensible.
var frozen = Object.freeze({});
Reflect.isExtensible(frozen); // === false
与 Object.isExtensible() 的不同点
如果该方法的第一个参数不是一个对象(原始值),那么将造成一个 TypeError 异常。对于 Object.isExtensible(),非对象的第一个参数会被强制转换为一个对象。
Reflect.isExtensible(1);
// TypeError: 1 is not an object
Object.isExtensible(1);
// false
定义:静态方法 Reflect.ownKeys() 返回一个由目标对象自身的属性键组成的数组。它的返回值等同于Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target))。
语法:
Reflect.ownKeys(target)
参数:target
获取自身属性键的目标对象。
返回值:由目标对象的自身属性键组成的 Array。
异常:如果目标不是 Object,抛出一个 TypeError。
示例:
Reflect.ownKeys({z: 3, y: 2, x: 1}); // [ "z", "y", "x" ]
Reflect.ownKeys([]); // ["length"]
var sym = Symbol.for("comet");
var sym2 = Symbol.for("meteor");
var obj = {[sym]: 0, "str": 0, "773": 0, "0": 0,
[sym2]: 0, "-1": 0, "8": 0, "second str": 0};
Reflect.ownKeys(obj);
// [ "0", "8", "773", "str", "-1", "second str", Symbol(comet), Symbol(meteor) ]
// Indexes in numeric order,
// strings in insertion order,
// symbols in insertion order
定义:静态方法 Reflect.preventExtensions() 方法阻止新属性添加到对象 (例如:防止将来对对象的扩展被添加到对象中)。该方法与Object.preventExtensions()相似。
语法:
Reflect.preventExtensions(target)
参数:target
阻止扩展的目标对象。
返回值:返回一个 Boolean 值表明目标对象是否成功被设置为不可扩展。
异常:抛出一个 TypeError 错误,如果 target 不是 Object。
示例:
// Objects are extensible by default.
var empty = {};
Reflect.isExtensible(empty); // === true
// ...but that can be changed.
Reflect.preventExtensions(empty);
Reflect.isExtensible(empty); // === false
与 Object.preventExtensions() 的不同点
如果该方法的 target 参数不是一个对象(是原始值),那么将造成一个 TypeError 异常。 对于Object.preventExtensions() 方法, 非对象的 target 参数将被强制转换为对象。
Reflect.preventExtensions(1);
// TypeError: 1 is not an object
Object.preventExtensions(1);
// 1
定义:静态方法 Reflect.set() 允许你在对象上设置属性。它的作用是给属性赋值并且就像 property accessor 语法一样,但是它是以函数的方式。
语法:
Reflect.set(target, propertyKey, value[, receiver])
参数:target
设置属性的目标对象、propertyKey
设置的属性的名称、value
设置的值、receiver
如果遇到 setter,receiver则为setter调用时的this值。
返回值:返回一个 Boolean 值表明是否成功设置属性。
异常:抛出一个 TypeError,如果目标不是 Object。
示例:
// Object
var obj = {};
Reflect.set(obj, "prop", "value"); // true
obj.prop; // "value"
// Array
var arr = ["duck", "duck", "duck"];
Reflect.set(arr, 2, "goose"); // true
arr[2]; // "goose"
// It can truncate an array.
Reflect.set(arr, "length", 1); // true
arr; // ["duck"];
// With just one argument, propertyKey and value are "undefined".
var obj = {};
Reflect.set(obj); // true
Reflect.getOwnPropertyDescriptor(obj, "undefined");
// { value: undefined, writable: true, enumerable: true, configurable: true }
定义:除了返回类型以外,静态方法 Reflect.setPrototypeOf() 与 Object.setPrototypeOf() 方法是一样的。它可设置对象的原型(即内部的 [[Prototype]] 属性)为另一个对象或 null,如果操作成功返回 true,否则返回 false。
语法:
Reflect.setPrototypeOf(target, prototype)
参数:target
设置原型的目标对象、prototype
对象的新原型(一个对象或 null)。
返回值:返回一个 Boolean 值表明是否原型已经成功设置。
异常:如果 target 不是 Object ,或 prototype 既不是对象也不是 null,抛出一个 TypeError 异常。
示例:
Reflect.setPrototypeOf({}, Object.prototype); // true
// It can change an object's [[Prototype]] to null.
Reflect.setPrototypeOf({}, null); // true
// Returns false if target is not extensible.
Reflect.setPrototypeOf(Object.freeze({}), null); // false
// Returns false if it cause a prototype chain cycle.
var target = {};
var proto = Object.create(target);
Reflect.setPrototypeOf(target, proto); // false
参考:
1.《Proxy - JavaScript | MDN》;
2.《Reflect - JavaScript | MDN》;