[解決済み] JavaScriptで動的なゲッター/セッターを実装することは可能ですか?
質問
以下のような方法で、すでに名前がわかっているプロパティに対してゲッターとセッターを作成する方法を知っています。
// A trivial example:
function MyObject(val){
this.count = 0;
this.value = val;
}
MyObject.prototype = {
get value(){
return this.count < 2 ? "Go away" : this._value;
},
set value(val){
this._value = val + (++this.count);
}
};
var a = new MyObject('foo');
alert(a.value); // --> "Go away"
a.value = 'bar';
alert(a.value); // --> "bar2"
さて、質問ですが、このようなキャッチオールなゲッターとセッターを定義することは可能でしょうか? つまり、以下のようなプロパティ名に対して、ゲッターとセッターを作成することができます。 でない場合 すでに定義されています。
このコンセプトは、PHPで
__get()
と
__set()
マジックメソッド (
PHPのドキュメント
ということで、これに相当するJavaScriptはないのでしょうか?
もちろん、クロスブラウザに対応したソリューションが理想的なのは言うまでもありません。
どのように解決するのですか?
ES2015 (別名: ES6") 仕様から変更されました。JavaScriptは現在
プロキシ
. プロキシは、他のオブジェクトの真のプロキシ(ファサード)となるオブジェクトを作成することができます。以下は、文字列のプロパティ値をすべて大文字に変換して返す簡単な例です。
"missing"
の代わりに
undefined
のように、存在しないプロパティに対して
"use strict";
if (typeof Proxy == "undefined") {
throw new Error("This browser doesn't support Proxy");
}
let original = {
example: "value",
};
let proxy = new Proxy(original, {
get(target, name, receiver) {
if (Reflect.has(target, name)) {
let rv = Reflect.get(target, name, receiver);
if (typeof rv === "string") {
rv = rv.toUpperCase();
}
return rv;
}
return "missing";
}
});
console.log(`original.example = ${original.example}`); // "original.example = value"
console.log(`proxy.example = ${proxy.example}`); // "proxy.example = VALUE"
console.log(`proxy.unknown = ${proxy.unknown}`); // "proxy.unknown = missing"
original.example = "updated";
console.log(`original.example = ${original.example}`); // "original.example = updated"
console.log(`proxy.example = ${proxy.example}`); // "proxy.example = UPDATED"
オーバーライドしない操作は、そのデフォルトの動作になります。上記の例では、オーバーライドするのは
get
しかし、あなたがフックすることができる操作の全リストがあります。
において
get
ハンドラ関数の引数リストです。
-
target
はプロキシされるオブジェクト (original
この例では)。 -
name
は(もちろん)取得されるプロパティの名前で、通常は文字列ですが、シンボルでもかまいません。 -
receiver
として使用されるべきオブジェクトです。this
は、プロパティがデータプロパティではなくアクセッサである場合、ゲッター関数の中にあります。通常の場合、これはプロキシかそれを継承したものですが、それは できる によってトラップが発生する可能性があるため、何でもありです。Reflect.get
.
これにより、必要なキャッチオールゲッターとセッターの機能を持つオブジェクトを作成することができます。
"use strict";
if (typeof Proxy == "undefined") {
throw new Error("This browser doesn't support Proxy");
}
let obj = new Proxy({}, {
get(target, name, receiver) {
if (!Reflect.has(target, name)) {
console.log("Getting non-existent property '" + name + "'");
return undefined;
}
return Reflect.get(target, name, receiver);
},
set(target, name, value, receiver) {
if (!Reflect.has(target, name)) {
console.log(`Setting non-existent property '${name}', initial value: ${value}`);
}
return Reflect.set(target, name, value, receiver);
}
});
console.log(`[before] obj.example = ${obj.example}`);
obj.example = "value";
console.log(`[after] obj.example = ${obj.example}`);
上記のように出力されます。
存在しないプロパティ 'example' の取得 [前] obj.example = undefined 存在しないプロパティ'example'の設定、初期値:value [後】 obj.example = value
を取得しようとすると、"non-existent" というメッセージが表示されることに注意してください。
example
がまだ存在しないとき、そしてそれを作成したとき、それ以後は存在しません。
2011年の回答 (Internet ExplorerのようなES5の機能に制限された環境では、まだ有効です。) :
いいえ、JavaScriptにはプロパティをキャッチオールする機能はありません。あなたが使っているアクセッサ構文は 11.1.5節 は、ワイルドカードやそのようなものを提供しません。
もちろん、それを実現するための関数を実装することもできますが、おそらくは
f = obj.prop("example");
よりも
f = obj.example;
と
obj.prop("example", value);
よりも
obj.example = value;
(これは、関数が未知のプロパティを処理するために必要です)。
参考までに、ゲッター関数(セッターのロジックは気にしませんでした)は次のようになります。
MyObject.prototype.prop = function(propName) {
if (propName in this) {
// This object or its prototype already has this property,
// return the existing value.
return this[propName];
}
// ...Catch-all, deal with undefined property here...
};
しかし、繰り返しになりますが、オブジェクトの使い方が変わってしまうので、本当にそうしたいとは思えません。
関連
-
[解決済み] Error : 未定義のプロパティ 'map' を読み取ることができません。
-
[解決済み】 `string.split is not a function` というエラーの原因は何ですか?
-
[解決済み] JavaScriptで "use strict "は何をするのか、その根拠は?
-
[解決済み] JavaScriptで文字列が部分文字列を含むかどうかを確認する方法は?
-
[解決済み] あるJavaScriptファイルを他のJavaScriptファイルにインクルードするにはどうすればよいですか?
-
[解決済み] JavaScriptでメールアドレスを検証するのに最適な方法は何ですか?
-
[解決済み] JavaScriptでタイムスタンプを取得する方法は?
-
[解決済み】JavaScriptの比較では、どちらの等号演算子(== vs ===)を使うべきですか?
-
[解決済み】JavaScriptで文字列の出現箇所をすべて置換する方法
-
[解決済み】オブジェクトからプロパティを削除する(JavaScript)
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
vue3レスポンシブ対応のためのsetup+ref+reactive
-
JavaScriptにおけるマクロタスクとミクロタスクの詳細
-
JavaScriptの配列共通メソッド解説
-
vueの補間表現とv-textディレクティブの違いについて
-
Vueのフォームイベントのデータバインディングの説明
-
[解決済み] TypeError: $.ajax(...) is not a function?
-
[解決済み】ERROR エラーです。スイッチのname属性が指定されていないフォームコントロールの値アクセッサがない
-
[解決済み】 `string.split is not a function` というエラーの原因は何ですか?
-
[解決済み】リクエストに失敗していないのに、「TypeError: failed to fetch」が表示される。
-
[解決済み】ReactJSでエラー発生 Uncaught TypeError: Super expression は null か関数でなければならず、undefined ではありません。