オブジェクトの(任意の)プロパティがアクセスされたとき、またはアクセスを試みたときにキャプチャすることは可能ですか?
例:
カスタムオブジェクトを作成しました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;
}
はい、これはES2015 +で、 Proxy を使用して可能です。 ES5以前では、ポリフィルを使用しても不可能です。
しばらく時間がかかりましたが、ついにこの質問に 私の前の答え を見つけました。プロキシなどの詳細については、その回答を参照してください。
その答えからのプロキシの例は次のとおりです。
const obj = new Proxy({}, {
get: function(target, name, receiver) {
if (!(name in target)) {
console.log("Getting non-existant property '" + name + "'");
return undefined;
}
return Reflect.get(target, name, receiver);
},
set: function(target, name, value, receiver) {
if (!(name in target)) {
console.log("Setting non-existant property '" + name + "', initial value: " + value);
}
return Reflect.set(target, name, value, receiver);
}
});
console.log("[before] obj.foo = " + obj.foo);
obj.foo = "bar";
console.log("[after] obj.foo = " + obj.foo);
obj.foo = "baz";
console.log("[after] obj.foo = " + obj.foo);
ライブコピー:
"use strict";
const obj = new Proxy({}, {
get: function(target, name, receiver) {
if (!(name in target)) {
console.log("Getting non-existant property '" + name + "'");
return undefined;
}
return Reflect.get(target, name, receiver);
},
set: function(target, name, value, receiver) {
if (!(name in target)) {
console.log("Setting non-existant property '" + name + "', initial value: " + value);
}
return Reflect.set(target, name, value, receiver);
}
});
console.log("[before] obj.foo = " + obj.foo);
obj.foo = "bar";
console.log("[after] obj.foo = " + obj.foo);
obj.foo = "baz";
console.log("[after] obj.foo = " + obj.foo);
実行すると、次のように出力されます。
存在しないプロパティの取得 'foo' [before] obj.foo = undefined 存在しないプロパティの設定 'foo'、初期値:bar [after] obj.foo = bar [after] obj.foo = baz
あなたが何かをデバッグしようとしているという仮定の下でこれを書きます。 Crowderが言ったように、これは新しいブラウザでのみ利用可能です。したがって、veryは、望まないことを実行するコードをテストするのに役立ちます。しかし、私は製品コードのためにそれを削除します。
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が私を殴ったようです。機能に関するMozillaのドキュメントもいくつかあります ここ 。
すでに回答したように、ECMAScript6の Proxy
オブジェクトを使用した場合にのみ可能になります。一方、ニーズや全体的な設計によっては、同様の実装を行うことでこれを実現できます。
例えば。
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;
他の回答が述べたように、現時点では未定義のプロパティを傍受する方法はありません。
しかし、これは受け入れられますか?
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
新しいdefineProperties
、defineGetter
、およびdefineSetter
がjavascriptに追加されると、多少似たようなことができます。ただし、オブジェクトの__properties__
を非表示にする本当の方法はまだありません。これを見ることをお勧めします 記事 。
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