ES6 入门教程 15 Proxy 15.2 Proxy 实例的方法 15.2.10 ownKeys() ~ 15.2.12 setPrototypeOf()
创始人
2024-02-04 05:28:53

ES6 入门教程

ECMAScript 6 入门

作者:阮一峰

本文仅用于学习记录,不存在任何商业用途,如侵删

文章目录

      • ES6 入门教程
      • 15 Proxy
        • 15.2 Proxy 实例的方法
          • 15.2.10 ownKeys()
          • 15.2.11 preventExtensions()
          • 15.2.12 setPrototypeOf()

15 Proxy

15.2 Proxy 实例的方法

拦截方法的详细介绍。

15.2.10 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()操作,只返回abc三个属性之中的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()指定只返回ab属性,由于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,所以导致了报错。

15.2.11 preventExtensions()

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

这个方法有一个限制,只有目标对象不可扩展时(即Object.isExtensible(proxy)false),proxy.preventExtensions才能返回true,否则会报错。

var proxy = new Proxy({}, {preventExtensions: function(target) {return true;}
});Object.preventExtensions(proxy)
// Uncaught TypeError: 'preventExtensions' on proxy: trap returned truish but the proxy target is extensible

上面代码中,proxy.preventExtensions()方法返回true,但这时Object.isExtensible(proxy)会返回true,因此报错。

为了防止出现这个问题,通常要在proxy.preventExtensions()方法里面,调用一次Object.preventExtensions()

var proxy = new Proxy({}, {preventExtensions: function(target) {console.log('called');Object.preventExtensions(target);return true;}
});Object.preventExtensions(proxy)
// "called"
// Proxy {}
15.2.12 setPrototypeOf()

setPrototypeOf()方法主要用来拦截Object.setPrototypeOf()方法。

下面是一个例子。

var handler = {setPrototypeOf (target, proto) {throw new Error('Changing the prototype is forbidden');}
};
var proto = {};
var target = function () {};
var proxy = new Proxy(target, handler);
Object.setPrototypeOf(proxy, proto);
// Error: Changing the prototype is forbidden

上面代码中,只要修改target的原型对象,就会报错。

注意,该方法只能返回布尔值,否则会被自动转为布尔值。另外,如果目标对象不可扩展(non-extensible),setPrototypeOf()方法不得改变目标对象的原型。

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...