5

I'm trying to create a function that hides private properties on Objects as well as possible. I would define private properties here as those that begin with an underscore, eg. _password.

Below is what I've got so far (thanks to Nicolas Bevacqua's great intro to proxies).

Now I was wondering:

  1. Am I covering all bases with the following code? Or am I missing an important proxy trap through which the objects could still be accessed?
  2. Is this the right way to use the Reflect methods in conjunction with a proxy? And do I even need them here?
  3. Are the values I return for private properties real enough to let people think that the property really does not exist?

My function so far:

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: For native browser support, you might have to look at it in MS Edge or Firefox Dev Edition.

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

4

2 に答える 2

3

「不変条件」の概念を認識する必要があります。たとえば、オブジェクトが拡張不可能な場合、プロキシを介してそのプロパティを非表示にすることは許可されず、構成不可能なプロパティを非表示にすることはできません。definePropertyまだ持っていないプロパティを 使用することはできません。getOwnPropertyDescriptorオブジェクトまたは を返す必要がありますundefineddeleteProperty構成不可能なプロパティは削除できません。set書き込み不可、構成不可のプロパティは変更できません。これらのいずれかまたはすべてが、さまざまなシナリオで (実行時にスローすることによって) コードが失敗する可能性があります。

その他の小さな問題にはset、ブール値 (成功/失敗) を返すことになっているという事実が含まれますが、返された がどうなるかはわかりませんundefined

于 2016-12-02T02:51:23.293 に答える
2

コードにはいくつかの問題があります。

  • 関数のパラメーターの部分throwError = throwErrorprivate不要です (実際、少なくとも最新の Chrome では機能しません)。これthrowErrorは、とにかく関数内で使用できるためです。
  • getOwnPropertyDescriptorトラップは決して返されませんfalseundefined存在しないプロパティに対して返される必要があります。
  • enumerateトラップは廃止されました
  • オブジェクトを呼び出すReflect.preventExtensions()と、proxiedオブジェクトが壊れます。preventExtensionsトラップを追加してその中に戻ることで、オブジェクトの拡張を妨げないようにする必要がありますfalse
于 2016-12-02T01:10:14.187 に答える