当我阅读有关ES6 Proxies的内容时,在我查看this example之前,它似乎很容易理解。
我很难过。我不明白他们使用的“湿/干”术语,我不知道什么时候我最终会遇到理想的选择,特别是因为我似乎无法找到它。
有人可以提供一个简短的解释,说明会出现这种情况的情况吗?
答案 0 :(得分:6)
首先,有一些基础知识:对象是属性的集合(其中一些是函数,正式命名为“方法”)。这可能听起来很明显,但重要的是:您通过对象和属性名称引用其他值。
代理允许您重写由(包含)对象的元组和属性名称引用其他值的规则。例如,您可以隐藏代理后面的“私人”成员。
但假设你有一个循环对象引用。例如,
var x = { z: function() { throw new Error("This shouldn't be callable"); };
var X = /* proxy representing x, where X.z is hidden and cannot be called */;
var y = { x: x };
x.y = y;
或者在文档对象模型术语中,document.documentElement.ownerDocument == document。
在普通代理中,引用X.y会返回y。那里没什么不对的......除了X.y.x === x和X.y.x!== X.所以我仍然可以打电话:
X.y.x.z(); // throws new Error("This shouldn't be callable")
Membranes所有关于确保非原始属性(对象和函数)保留此身份关系,并通过任何属性查找组合维护您所拥有的任何代理规则。膜可以防止您意外地直接访问各种对象的底层(可能是原生的)实现。
如果X是x的基于膜的代理,则X.y将不返回y。相反,它将返回y的代理,我将其称为Y.Y暴露y的属性,就像X暴露x的属性一样。
更重要的是,假设我引用了X.y.x:
X.y.x === X; // true
X.y.x !== x; // also true
typeof X.y.x.z // returns "undefined", not "function"
X.y.x.z(); // throws TypeError("X.y.x.z is not a function")
通过膜返回对X(x的代理)的引用。因此,保留了身份属性。 (x.y.x === x,所以X.y.x === X。)
这是最重要的概念:膜意味着您可能永远不会看到原始对象,只能看到代表它们的代理对象。
var X = (function() {
var x = { z: function() { throw new Error("This shouldn't be callable"); };
var y = { x: x };
x.y = y;
var X = /* membrane proxy representing x, where X.z is hidden and cannot be called */;
return X;
})();
X.y.x === X; // still true
在Tom van Cutsem's articles on JavaScript Membranes中,其中一个cited above,值x,y和xz都可以被视为“湿”对象图的一部分,而通过X或Y引用的任何内容都会成为“干”对象图的一部分。 (此处的术语图来自图论,是离散数学研究的一部分。对象图表示一组相关对象,而膜是将“本机”对象集与代理集分隔为这些对象。 )
x和y值直接从函数外部无法访问。 (用JavaScript的说法,在这个例子中,它们是局部变量,但从膜的角度来看,这部分是误导性的:如果我们谈论DOM文档,那么你真正在网络浏览器中获得的东西就像Mozilla Firefox一样代表了DOM文档,而不是来自本机内存的实际文档对象。无论是局部变量还是插入到您正在运行的JavaScript范围内的值,膜及其代理都不关心。)
相反,你对x,y及其属性的唯一访问是通过X膜代理,以及从X获得的任何属性。因为它是一个膜,所以访问总是间接的。
对于会发生这种情况的情况:假设您拥有可以执行各种操作的可信代码,例如访问计算机的文件系统。您不希望网页能够直接从文件系统读取,或者更糟糕的是,写入它。代理膜通过仅暴露您打算公开的属性和方法,减少了网页可以使用的API,因此不太可能意外访问该可信代码。这使安全漏洞更加罕见。
最重要的是,如果膜实现是正确的(这比听起来要难得多),网页JavaScript不知道或不关心它正在处理代理。网页脚本认为它是处理普通的DOM。这就是我们想要的。