javascript 代理真的可以提供对类的私有字段的访问吗?

vm0i2vca  于 2023-06-04  发布在  Java
关注(0)|答案(1)|浏览(158)

我正在阅读这里的文档,它似乎暗示即使是私有字段,也可以通过代理访问它们。请参阅以“....要修复此....”开头的简介。但给出的例子,不起作用。我的代码如下所示:
具有private字段的类:

class Danger {
    #areYouSure = "magic";

    grave(){
        console.log("Yes, grave danger");
        return true;
    }

}

module.exports = Danger;

正在尝试使用代理访问它:

const Danger = require('./testing-private');

const handler = {
    get(target, property, receiver){
        return target[property];
    }
};
const dangerProxy = new Proxy(new Danger(), handler);

console.log("--------------------------------------", dangerProxy.areYouSure);

这将输出:

-------------------------------------- undefined

如果我将“dangerProxy.areYouSure”替换为“dangerProxy.#areYouSure”。我明白

/home/zaphod/code/math/js-experiments/src/danger-proxy.js:29
console.log("--------------------------------------", dangerProxy.#areYouSure);
                                                                 ^

SyntaxError: Private field '#areYouSure' must be declared in an enclosing class
    at Object.compileFunction (node:vm:352:18)
    at wrapSafe (node:internal/modules/cjs/loader:1032:15)
    at Module._compile (node:internal/modules/cjs/loader:1067:27)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1155:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)
    at node:internal/main/run_main_module:17:47

有没有办法让这个工作或我的期望是不正确的?

rsl1atfo

rsl1atfo1#

文档的这一部分实际上是关于getter属性中的this(尽管它不是很清楚),而不是关于私有属性本身。只是当getter访问私有字段时,getter中this的值更重要。
假设我们使用一个伪私有属性(仅按约定为私有)来做同样的事情:

class Secret {
    _secret;
    constructor(secret) {
        this._secret = secret;
    }
    get secret() {
        return this._secret.replace(/\d+/, "[REDACTED]");
    }
}

const aSecret = new Secret("123456");
console.log(aSecret.secret); // [REDACTED]
// Looks like a no-op forwarding...
const proxy = new Proxy(aSecret, {});
console.log(proxy.secret); // [REDACTED]

如你所见,这是有效的。但是为什么当一个真正的私人领域不起作用的时候它却起作用了呢?因为在getter调用期间this的值。让我们看看this是什么:

class Secret {
    _secret;
    constructor(secret) {
        this._secret = secret;
    }
    get secret() {
        console.log(`this === aSecret? ${this === aSecret}`);
        console.log(`this === proxy? ${this === proxy}`);
        return this._secret.replace(/\d+/, "[REDACTED]");
    }
}

const aSecret = new Secret("123456");
const proxy = new Proxy(aSecret, {}); // (Had to move this, but it doesn't change anything important)
console.log(aSecret.secret); // [REDACTED]
console.log(proxy.secret); // [REDACTED]

当我们直接使用aSecret时,this是(也许很明显)aSecret

this === aSecret? true
this === proxy? false
[REDACTED]

...但是当我们通过代理时,this是代理:

this === aSecret? false
this === proxy? true
[REDACTED]

这是因为get陷阱的默认实现实际上看起来像这样:

get(target, propName, receiver) {
    return Reflect.get(target, propName, receiver);
}

proxy.secret中,target将是aSecretpropName将是"secret"receiver将是proxyReflect.get将使用receiver(代理)作为this调用getter函数,因为这是第三个参数的作用,即在操作期间this的值。this在操作期间是proxy而不是aSecret对于我们的伪私有示例来说并不重要,因为当getter方法试图访问this._secret时,它会在代理上访问它,然后从目标获取它。但这对真正的私有字段不起作用,因为代理对象没有私有字段。
他们提供的解决方案是将get陷阱从上面的默认设置更改为:

get(target, propName, receiver) {
    return target[propName];
    // The above is like `return Reflect.get(target, propName, target);`
    // Note `target` instead of `receiver` for third argument −^
}

这样,getter方法中的thistargetaSecret),而不是receiverproxy),因此可以访问私有字段。
代理真的可以提供对类的私有字段的访问吗?
代理不能公开一个示例的私有字段,该示例还没有提供访问私有字段的非私有方式。但是它可以提供对getter和方法的访问,这些getter和方法可以访问这些字段。但是你必须提供正确的this

相关问题