访问JavaScript对象的默认getter / setter

Access default getter/setter for JavaScript object

可以使用Object.defineProperty为特定属性重写javascript getter和setter。是否有方法访问默认的getter/setter(即,如果getter/setter未被覆盖,则使用的函数)?在自定义setter中,我希望在某些情况下进行特殊处理,但在其他情况下使用默认处理。我尝试过:

1
2
3
4
5
6
7
8
9
10
Object.defineProperty(obj, 'foo',
  'set': function(val) {
    if (useCustom) {
      doCustomProcessing(obj, 'foo', val);
    }
    else {
      obj['foo'] = val;
    }
  }
);

不幸的是,这会导致堆栈溢出,因为obj['foo'] = val;会导致调用自定义setter。因此,我想找到一种方法来使用默认的setter设置objfoo属性。这有可能吗?


据我所知,一个属性要么有一个值(data属性),要么有getter/setter(accessor属性):它不能两者都有。使用闭包下的局部变量或其他属性作为定义了getter/setter的属性的基础存储。

例如,

1
2
3
4
5
6
7
8
9
10
11
12
13
(function() {
    var value;
    Object.defineProperty(obj, 'foo', {
      set: function(val) {
        if (useCustom) {
          value = doCustomProcessing(obj, 'foo', val);
        } else {
          value = val;
        }
      },
      get: function() { return value; }
    });
})();


在ES6中,可以使用代理对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var myObject = {};

var myProxyObject = new Proxy(myObject, {
  set: function(ob, prop, value) {
    if (prop === 'counter' && value === 10) {
      // Some specialised behaviour
      ob.counter = 0;
    }
    else {
      // Default setter behaviour.
      ob[prop] = value;
    }
    // Return true otherwise you will get a TypeError in strict mode.
    return true;
  }
});

>>> myProxyObject.counter = 5;
>>> console.log(myProxyObject.counter);
5

>>> myProxyObject.counter = 10;
>>> console.log(myProxyObject.counter);
0


我知道如何做到这一点的唯一方法是使变量非私有化,但有两个例子,第二个更简单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
(function testInheritance(global, doc) {
 "use strict";
  var MyFunc = Object.create({}, {
      _foo: {
        value:"Some Default Value",
        writable: true,
        enumerable: true
      },
      foo: {
        get: function() {
          return this._foo;
        },
        set: function(value) {
          this._foo = value;
        }
      }
    }),
    testFunc = Object.create(MyFunc);
  console.log(testFunc.foo); //"Some default value"
  testFunc.foo ="boo";
  console.log(testFunc.foo); //"boo";
 testFunc._foo ="Not a private variable anymore";
 console.log(testFunc.foo); //"Not a private variable anymore"
}(window, document));

(function testInheritanceTwo(global, doc) {
 "use strict";
  var MyFunc = Object.create({}, {
      foo: {
        get: function() {
          if (!this._foo) {
             return"Some default value set by the getter.";
          }
          return this._foo;
        },
        set: function(value) {
          this._foo = value;
        }
      }
    }),
    testFunc = Object.create(MyFunc);
  console.log(testFunc.foo); //"Some default value set by the getter."
  testFunc.foo ="Whomp";
  console.log(testFunc.foo); //"Whomp";
 testFunc._foo ="Not a private variable anymore, unfortunately.";
 console.log(testFunc.foo); //"Not a private variable anymore"
}(window, document));

据我所知:

  • 不能引用与set:function(value)中使用的名称相同的值,也不能以无限循环结束,在该循环中,设置值将调用set值并再次调用自身,依此类推。因此,你的问题。

  • 如果试图将变量foo设为private,则setter不起作用。使用这种语法,您似乎可以隐藏变量,但不能真正将其设置为私有。