Skip to content

ownKeys() ​

本节目标:理解“ownKeys()”的核心思路,并能把它用于实际开发或面试表达。 ownKeys方法用来拦截对象自身属性的读取操作。具体来说,拦截以下操作。

Object.getOwnPropertyNames()
Object.getOwnPropertySymbols()
Object.keys()
for...in循环
下面是拦截Object.keys()的例子。
let target = {  a: 1,  b: 2,  c: 3};
let handler = {  ownKeys(target) {    return ['a'];  }};
let proxy = new Proxy(target, handler);
Object.keys(proxy)// [ 'a' ]
上面代码拦截了对于target对象的Object.keys()操作,只返回a、b、c三个属性之中的a属性。
下面的例子是拦截第一个字符为下划线的属性名。
let target = {  _bar: 'foo',  _prop: 'bar',  prop: 'baz'};
let handler = {  ownKeys (target) {    return Reflect.ownKeys(target).filter(key => key[0] !== '_');  }};
let proxy = new Proxy(target, handler);for (let key of Object.keys(proxy)) {  console.log(target[key]);}// "baz"
注意,使用Object.keys方法时,有三类属性会被ownKeys方法自动过滤,不会返回。
目标对象上不存在的属性
属性名为 Symbol 值
不可遍历(enumerable)的属性
let target = {  a: 1,  b: 2,  c: 3,  [Symbol.for('secret')]: '4',};
Object.defineProperty(target, 'key', {  enumerable: false,  configurable: true,  writable: true,  value: 'static'});
let handler = {  ownKeys(target) {    return ['a', 'd', Symbol.for('secret'), 'key'];  }};
let proxy = new Proxy(target, handler);
Object.keys(proxy)// ['a']
上面代码中,ownKeys方法之中,显式返回不存在的属性(d)、Symbol 值(Symbol.for('secret'))、不可遍历的属性(key),结果都被自动过滤掉。
ownKeys方法还可以拦截Object.getOwnPropertyNames()。
var p = new Proxy({}, {  ownKeys: function(target) {    return ['a', 'b', 'c'];  }});
Object.getOwnPropertyNames(p)// [ 'a', 'b', 'c' ]
for...in循环也受到ownKeys方法的拦截。
const obj = { hello: 'world' };const proxy = new Proxy(obj, {  ownKeys: function () {    return ['a', 'b'];  }});
for (let key in proxy) {  console.log(key); // 没有任何输出}
上面代码中,ownkeys指定只返回a和b属性,由于obj没有这两个属性,因此for...in循环不会有任何输出。
ownKeys方法返回的数组成员,只能是字符串或 Symbol 值。如果有其他类型的值,或者返回的根本不是数组,就会报错。
var obj = {};
var p = new Proxy(obj, {  ownKeys: function(target) {    return [123, true, undefined, null, {}, []];  }});
Object.getOwnPropertyNames(p)// Uncaught TypeError: 123 is not a valid property name
上面代码中,ownKeys方法虽然返回一个数组,但是每一个数组成员都不是字符串或 Symbol 值,因此就报错了。
如果目标对象自身包含不可配置的属性,则该属性必须被ownKeys方法返回,否则报错。
var obj = {};Object.defineProperty(obj, 'a', {  configurable: false,  enumerable: true,  value: 10 });
var p = new Proxy(obj, {  ownKeys: function(target) {    return ['b'];  }});
Object.getOwnPropertyNames(p)// Uncaught TypeError: 'ownKeys' on proxy: trap result did not include 'a'
上面代码中,obj对象的a属性是不可配置的,这时ownKeys方法返回的数组之中,必须包含a,否则会报错。
另外,如果目标对象是不可扩展的(non-extensible),这时ownKeys方法返回的数组之中,必须包含原对象的所有属性,且不能包含多余的属性,否则报错。
var obj = {  a: 1};
Object.preventExtensions(obj);
var p = new Proxy(obj, {  ownKeys: function(target) {    return ['a', 'b'];  }});
Object.getOwnPropertyNames(p)// Uncaught TypeError: 'ownKeys' on proxy: trap returned extra keys but proxy target is non-extensible
上面代码中,obj对象是不可扩展的,这时ownKeys方法返回的数组之中,包含了obj对象的多余属性b,所以导致了报错。

本站总访问 — 次