是否可以捕获对象的(任何)属性何时被访问或尝试访问?
示例:
我创建了自定义对象Foo
var Foo = (function(){
var self = {};
//... set a few properties
return self;
})();
然后针对Foo
采取了一些行动 - 有人试图访问财产bar
Foo.bar
是否有方法(原型,也许)捕获这个? bar
上可能未定义Foo
。我可以捕获任何尝试访问未定义属性的功能。
例如,如果在bar
上未定义Foo
,并且尝试Foo.bar
,则类似:
Foo.prototype.undefined = function(){
var name = this.name; //name of property they attempted to access (bar)
Foo[name] = function(){
//...do something
};
return Foo[name];
}
但功能性,不像我的例子。
概念
Foo.* = function(){
}
背景
如果我有一个自定义函数,每次调用此函数时我都可以监听(见下文)。只是想知道是否可以进行财产访问。
Foo = function(){};
Foo.prototype.call = function(thisArg){
console.log(this, thisArg);
return this;
}
答案 0 :(得分:25)
这可以在ECMAScript6中使用,现在可以在Firefox上使用新的proxy stuff。在那之前,不,我担心没有办法挂钩。
我花了一段时间,但我终于找到了my previous answer这个问题。有关代理等的所有详细信息,请参阅该答案。
以下是该答案的代理示例:
var obj = new Proxy({}, {
get: function(target, name) {
if (!(name in target)) {
console.log("Getting non-existant property '" + name + "'");
return undefined;
}
return target[name];
},
set: function(target, name, value) {
if (!(name in target)) {
console.log("Setting non-existant property '" + name + "', initial value: " + value);
}
target[name] = value;
}
});
console.log("[before] obj.foo = " + obj.foo);
obj.foo = "bar";
console.log("[after] obj.foo = " + obj.foo);
Live Copy (目前仅适用于Firefox) | Source
运行时,输出:
Getting non-existant property 'foo' [before] obj.foo = undefined Setting non-existant property 'foo', initial value: bar [after] obj.foo = bar
答案 1 :(得分:4)
我会在你尝试调试某些东西的假设下写这个。正如克劳德所说,这只适用于较新的浏览器;因此,非常对于测试执行您不想要的代码的代码非常有用。但是,我将其删除以用于生产代码。
Object.defineProperty(Foo, 'bar', {
set: function() {
debugger; // Here is where I'll take a look in the developer console, figure out what's
// gone wrong, and then remove this whole block.
}
});
看起来megawac打败了我。您还可以找到有关功能here的一些Mozilla文档。
答案 2 :(得分:1)
就像已经回答的那样,只能使用ECMAScript6中的Proxy
对象。同时,根据您的需求和整体设计,您仍然可以通过实现类似的功能来实现这一目标。
E.g。
function WrappingProxy(object, noSuchMember) {
if (!this instanceof WrappingProxy) return new WrappingProxy(object);
this._object = object;
if (noSuchMember) this.noSuchMember = noSuchMember;
}
WrappingProxy.prototype = {
constructor: WrappingProxy,
get: function (propertyName) {
var obj = this._object;
if (propertyName in obj) return obj[propertyName];
if (this.noSuchMember) this.noSuchMember(propertyName, 'property');
},
set: function (propertyName, value) {
return this._object[propertyName] = value;
},
invoke: function (functionName) {
var obj = this._object,
args = Array.prototype.slice.call(arguments, 1);
if (functionName in obj) return obj[functionName].apply(obj, args);
if (this.noSuchMember) {
this.noSuchMember.apply(obj, [functionName, 'function'].concat(args));
}
},
object: function() { return this._object },
noSuchMember: null
};
var obj = new WrappingProxy({
testProp: 'test',
testFunc: function (v) {
return v;
}
},
//noSuchMember handler
function (name, type) {
console.log(name, type, arguments[2]);
}
);
obj.get('testProp'); //test
obj.get('nonExistingProperty'); //undefined, call noSuchMember
obj.invoke('testFunc', 'test'); //test
obj.invoke('nonExistingFunction', 'test'); //undefined, call noSuchMember
//accesing properties directly on the wrapped object is not monitored
obj.object().nonExistingProperty;
答案 3 :(得分:0)
将新的defineProperties
,defineGetter
和defineSetter
添加到javascript后,您可以执行类似的操作。但是,仍然没有真正的方法来隐藏对象的__properties__
。我建议你看看article。
var obj = {
__properties__: {
a: 4
}
}
Object.defineProperties(obj, {
"b": { get: function () { return this.__properties__.a + 1; } },
"c": { get: function (x) { this.__properties__.a = x / 2; } }
});
obj.b // 2
obj.c // .5
这是应该适用于任何环境的经典模型
//lame example of a model
var Model = function(a) {
this.__properties__ = {a: a};
}
Model.prototype.get = function(item) {
//do processing
return this.__properties__[item];
}
Model.prototype.set = function(item, val) {
//do processing
this.__properties__[item] = val;
return this;
}
var model = new Model(5);
model.get("a") // => 5
答案 4 :(得分:0)
正如其他答案所提到的那样,目前无法拦截未定义的属性。
这会被接受吗?
var myObj = (function() {
var props = {
foo : 'foo'
}
return {
getProp : function(propName) { return (propName in props) ? props[propName] : 'Nuh-uh!' }
}
}());
console.log(myObj.getProp('foo')); // foo
console.log(myObj.getProp('bar')); // Nuh-uh