如何拦截使用文字表示法创建的未知对象的已知 属性 赋值

How to intercept a known property value assignment of an unknwon object created using literal notation

这个问题是我在这里问的另一个问题的延续:

这个方法是用来拦截任何对象的属性某个名字的objective在赋值或读取时改变值或做某个动作:

Object.defineProperty(Object.prototype, "my_property", {
    set: function (value) {
        this._value = value;
    },
    get: function () {
        return "changed";
    }
});

var some_object = {};

some_object.my_property = "unchanged";


document.body.innerHTML += some_object.my_property;
My property value is: 

虽然在创建对象后该方法对于分配给属性或从属性读取的值工作正常,示例:

var some_object = {}; // or new Object()
some_object.some_property = "some_value"; // triggers setter
console.log(some_object.some_property);   // triggers getter

如果属性已经和对象一起使用文字符号初始化,它不会触发getter和setter,像这样:

var some_object = {some_property: "some_value"}; // does not trigger setter
console.log(some_object.some_property);          // does not trigger getter

我如何调整之前的策略,以便它也可以使用文字表示法,或者是否有使用完全不同的方法实现此目的的不同方法?也许通过文字符号拦截任何对象的创建,类似于猴子修补 Object.create() 函数?

请记住,这只是针对任何未知对象上的 属性 已知名称。

我不知道有什么方法可以达到您想要的效果。使用 = 的赋值将导致您的对象通过原型链并在对象原型上使用 get 方法。但是,文字赋值会将其直接放置在您的新对象上。这是Javascript的规则。有关更多信息,我建议阅读 You Don't Know JS, This & Object Prototypes,第 5 章,特别是 Setting & Shadowing Properties 部分。

相关部分:

We will now examine three scenarios for the myObject.foo = "bar" assignment when foo is not already on myObject directly, but is at a higher level of myObject's [[Prototype]] chain:

  1. If a normal data accessor (see Chapter 3) property named foo is found anywhere higher on the [[Prototype]] chain, and it's not marked as read-only (writable:false) then a new property called foo is added directly to myObject, resulting in a shadowed property.
  2. If a foo is found higher on the [[Prototype]] chain, but it's marked as read-only (writable:false), then both the setting of that existing property as well as the creation of the shadowed property on myObject are disallowed. If the code is running in strict mode, an error will be thrown. Otherwise, the setting of the property value will silently be ignored. Either way, no shadowing occurs.
  3. If a foo is found higher on the [[Prototype]] chain and it's a setter (see Chapter 3), then the setter will always be called. No foo will be added to (aka, shadowed on) myObject, nor will the foo setter be redefined. Most developers assume that assignment of a property ([[Put]]) will always result in shadowing if the property already exists higher on the [[Prototype]] chain, but as you can see, that's only true in one (#1) of the three situations just described.

If you want to shadow foo in cases #2 and #3, you cannot use = assignment, but must instead use Object.defineProperty(..) (see Chapter 3) to add foo to myObject.