使用ES6代理隐藏私有属性

Using ES6 Proxies to hide private properties

本文关键字:属性 隐藏 ES6 代理 使用      更新时间:2023-09-26

我试图创建一个函数,隐藏对象上的私有属性以及尽可能。我在这里将私有属性定义为以下划线开头的属性,例如。_password .

下面是我到目前为止得到的(感谢Nicolas Bevacqua对代理的伟大介绍)。

现在我在想:

  1. 我覆盖所有基地与以下代码?或者我错过了一个仍然可以访问对象的重要代理陷阱?
  2. 这是使用Reflect方法与代理结合的正确方法吗?我在这里还需要它们吗?
  3. 我为私有属性返回的值是否足够真实,让人们认为该属性真的不存在?

我的功能:

function privatize(obj, prefix = '_', throwError = false) {
  const proxyHandler = {
    get(target, key) {
        return private(key, 'get') ? undefined : Reflect.get(target, key);
      },
      set(target, key, value) {
        return private(key, 'set') ? undefined : Reflect.set(target, key, value);
      },
      has(target, key) {
        return private(key, 'has') ? false : Reflect.has(target, key);
      },
      deleteProperty(target, key) {
        return private(key, 'delete') ? false : Reflect.deleteProperty(target, key);
      },
      defineProperty(target, key, descriptor) {
        return private(key, 'defineProperty') ? false : Reflect.defineProperty(target, key, descriptor);
      },
      enumerate(target) {
        return Object.keys().filter((key) => {
          return !private(key, null, false);
        })[Symbol.iterator]();
      },
      ownKeys(target) {
        return Reflect.ownKeys(target).filter((key) => {
          return !private(key, null, false);
        });
      },
      getOwnPropertyDescriptor(target, key) {
        return private(key, 'getOwnPropertyDescriptor') ? false : Reflect.getOwnPropertyDescriptor(target, key);
      }
  };
  function private(key, operationName) {
    if (key.indexOf(prefix) === 0) {
      if (throwError) {
        throw new Error(`Operation '${operationName}' is not allowed on private properties.`);
      }
      return true;
    }
  }
  return new Proxy(obj, proxyHandler);
}
var o = {
  first: 'should work',
  _second: 'should fail'
};
var proxied = privatize(o);
console.log(proxied);

PS:对于原生浏览器的支持,你可能需要在MS Edge或Firefox Dev Edition中查看它。

http://jsfiddle.net/bkd7mde7/1/

您需要了解"不变量"的概念。例如,如果一个对象是不可扩展的,那么它就不允许通过代理隐藏其属性,并且不可配置的属性也不能被隐藏。你不能defineProperty一个它没有的属性。getOwnPropertyDescriptor必须返回一个对象或undefineddeleteProperty不能删除不可配置的属性。set不能修改不可写、不可配置的属性。在各种情况下,任何或所有这些都可能导致代码失败(通过在运行时抛出)。

其他小问题包括set应该返回一个布尔值(成功/失败),尽管我不确定您返回的undefined会发生什么。

您的代码有几个问题:

  • private函数参数中的throwError = throwError部分是多余的(事实上甚至不起作用,至少在最新的Chrome中),因为throwError无论如何都将在函数内可用。
  • getOwnPropertyDescriptor trap不应该返回false。对于不存在的属性应该返回undefined
  • enumerate陷阱已经过时了。
  • proxied对象上调用Reflect.preventExtensions()会破坏它。您应该通过添加preventExtensions陷阱并在其中返回false来防止对象的扩展。