2013-11-22 153 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

好吧,我明白你在那裏做什麼。 –