2013-11-22 152 views
13

是否有可能在对象的(任何)属性被访问或尝试访问时捕获?Javascript - 捕获对象属性

例子:

我已创建自定义对象Foo

var Foo = (function(){ 
    var self = {}; 
    //... set a few properties 
    return self; 
})(); 

再有就是对Foo一些动作 - 有人试图访问属性bar

Foo.bar 

有没有办法(原型,也许)来捕捉这个? bar可能未定义在Foo上。我可以充分捕获任何尝试访问未定义的属性。

例如,如果barFoo不定,所以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; 
} 
+1

除非你为属性创建getter和setters并且“隐藏”真实属性 – megawac

+0

@megawac你可以发布一个简短的例子作为答案吗?我觉得我不需要太多,只是朝着正确的方向前进。 –

+0

很确定它不能完成 – SpliFF

回答

16

这将有可能在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(目前仅适用于火狐) | Source

运行时,输出:

Getting non-existant property 'foo' 
[before] obj.foo = undefined 
Setting non-existant property 'foo', initial value: bar 
[after] obj.foo = bar
+1

我倾向于同意,这是很好的信息,但我会坚持一会儿,然后再接受这一点。有时候我对黑巫术巫术人的想法感到惊讶。 –

+0

@RandyHall:可悲的是,在这种情况下,我相当肯定没有巫毒可用。 :-)查看上面链接的上一个答案(最初来自2011年)。 –

+0

因为你似乎得到了我要去的地方... Javascript试图找到一个属性,如果找不到,尝试在原型中找到该属性(从我的理解) - 可以沿着Foo.prototype.prototype行吗?我可以通过原型图层捕获JavaScript嗅探并对此做出反应吗? –

0

随着新添加的JavaScript definePropertiesdefineGetterdefineSetter,你可以做有点类似。但是,仍然没有真正的方法来隐藏对象的__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 
+2

良好的信息,但不完成我所拍摄的。我试图通过定义访问它的每个属性来防止“未定义”。每次有人试图访问对象的未定义属性时,我都想调用一个函数,在对象本身内部使用函数。 –

3

我你想调试东西的假设下写这个。正如Crowder所说,这只适用于较新的浏览器;所以它的非常有用测试代码,做你不想要的东西。但是,我删除它的生产代码。

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文档。

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 
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; 
+0

我非常感兴趣。你能为此添加一个小例子用法吗? –

+0

@RandyHall你有没有看过代码的最后?有一个使用示例。基本上你可以将任何对象包装到WrappingProxy中,然后通过方法调用(包括属性访问)执行所有交互。基本上你必须避免使用非包装版本的对象,如果你想这是一致的。如果您有一个非常具体的用例来捕获不存在的属性,则可以使用这种方法。 – plalx

+0

好吧,我明白你在那里做什么。 –