什么是身份保护膜代理的用例?

时间:2016-04-02 02:01:35

标签: javascript metaprogramming es6-proxy

当我阅读有关ES6 Proxies的内容时,在我查看this example之前,它似乎很容易理解。

我很难过。我不明白他们使用的“湿/干”术语,我不知道什么时候我最终会遇到理想的选择,特别是因为我似乎无法找到它。

有人可以提供一个简短的解释,说明会出现这种情况的情况吗?

1 个答案:

答案 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。这就是我们想要的。