如何拦截使用文字表示法创建的未知对象的已知 属性 赋值
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:
- 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.
- 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.
- 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.
这个问题是我在这里问的另一个问题的延续:
这个方法是用来拦截任何对象的属性某个名字的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:
- 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.
- 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.
- 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.