いつ使うべきか迷っています
Object.defineProperty
オブジェクトの新しいプロパティを作成します。私は次のようなものを設定できることを知っています
enumerable: false
しかし、これが本当に必要なのはいつですか?あなただけのようなプロパティを設定した場合
myObject.myprop = 5;
その記述子はすべてtrueに設定されていますよね?皆さんが.defineProperty()へのかなり冗長な呼び出しを使用するとき、そしてその理由について、私は実際にもっと興味があります。
_Object.defineProperty
_ は主に、特定のプロパティ記述子(たとえば、読み取り専用(定数)、列挙可能性( for (.. in ..)
ループ、ゲッター、セッター)。
_"use strict";
var myObj = {}; // Create object
// Set property (+descriptor)
Object.defineProperty(myObj, 'myprop', {
value: 5,
writable: false
});
console.log(myObj.myprop);// 5
myObj.myprop = 1; // In strict mode: TypeError: myObj.myprop is read-only
_
このメソッドは、Object
プロトタイプをプロパティで拡張します。ゲッターのみが定義され、列挙可能性はfalse
に設定されます。
_Object.defineProperty(Object.prototype, '__CLASS__', {
get: function() {
return Object.prototype.toString.call(this);
},
enumerable: false // = Default
});
Object.keys({}); // []
console.log([].__CLASS__); // "[object Array]"
_
「列挙可能」などの機能は、私の経験ではほとんど使用されていません。主なユースケースは計算されたプロパティです:
var myObj = {};
myObj.width = 20;
myObj.height = 20;
Object.defineProperty(myObj, 'area', {
get: function() {
return this.width*this.height;
}
});
console.log(myObj.area);
Object.definePropertyを使用する本当に良い理由は、オブジェクトの関数を計算されたプロパティとしてループできるため、関数の本体を返す代わりに関数を実行するためです。
例えば:
var myObj = {};
myObj.width = 20;
myObj.height = 20;
Object.defineProperty(myObj, 'area', {
get: function() {
return this.width*this.height;
},
enumerable: true
});
for (var key in myObj) {
if (myObj.hasOwnProperty(key)) {
console.log(key + " -> " + myObj[key]);
}
}
//width -> 20, height -> 20, area -> 400
関数をプロパティとしてオブジェクトリテラルに追加する場合:
var myObj = {};
myObj.width = 20;
myObj.height = 20;
myObj.area = function() {
return this.width*this.height;
};
for (var key in myObj) {
if (myObj.hasOwnProperty(key)) {
console.log(key + " -> " + myObj[key]);
}
}
// width -> 20, height -> 20, area -> function() { return this.width*this.height;}
列挙するプロパティをループするために、必ずtrueに設定してください。
たとえば、 Vue.jsがdata
オブジェクトの変更を追跡しているものです :
プレーンJavaScriptオブジェクトをVueインスタンスとして
data
オプションとして渡すと、Vueはすべてのプロパティをウォークスルーして変換しますgetter/setters
を使用してObject.defineProperty
に変換します。これはES5のみでシムできない機能であるため、VueはIE8以下をサポートしていません。ゲッター/セッターはユーザーには見えませんが、内部ではVueを有効にして、プロパティがアクセスまたは変更されたときに依存関係の追跡と変更通知を実行できます。
[...]
Vue.jsの非常にスリムでベーシックなバージョンでもObject.defineProperty
以外のものも使用しますが、主な機能は次のとおりです。
ここでは、著者がVue.jsのようなものの最小バージョンのPoCバージョンを実装している記事を見ることができます。 https://medium.com/js-dojo/understand-vue-reactivity-implementation-step-by- step-599c3d51cd6c
そして、Vue.jsで反応性を説明しながら話者が似たようなものを作成する(スペイン語の)トーク: https://www.youtube.com/watch?v=axXwWU-L7RM
私がdefineProperty
で見たきちんとした使用例の1つは、ライブラリがユーザーにエラープロパティを提供することです。これは、一定の時間内にアクセスされないと、自分自身をスローすることになります。例えば:
let logErrorTimeoutId = setTimeout(() => {
if (error) {
console.error('Unhandled (in <your library>)', error.stack || error);
}
}, 10);
Object.defineProperty(data, 'error', {
configurable: true,
enumerable: true,
get: () => {
clearTimeout(logErrorTimeoutId);
return error;
},
});
良い使い方は、インターセプトを行う必要がある場合や、古典的なObserver/Observableパターンをエレガントな方法で適用する必要がある場合です。
_Object.defineProperty
_は、プロトタイプチェーンのキーに誤って値を割り当てることを防ぎます。この方法では、特定のオブジェクトレベルのみに割り当てます(プロトタイプチェーンのキーには割り当てません)。
例:_{key1: value1, key2: value2}
_のようなオブジェクトがあり、そのプロトタイプチェーンを正確に知らないか、誤って見逃し、プロトタイプチェーンのどこかにプロパティ 'color'がある場合-
ドット(。)割り当てを使用
この操作は、プロトタイプチェーンのキー 'color'に値を割り当てます(キーがどこかに存在する場合)。変更のないオブジェクトがとして見つかります。 obj.color = 'blue'; // objは{key1:value1、key2:value2}と同じままです
Object.definePropertyメソッドを使用-
_Object.defineProperty(obj, 'color', {
value: 'blue'
});
_
// objは_{key1: value1, key2: value2, color: 'blue'}
_のようになります。同じレベルにプロパティを追加します。次に、メソッドObject.hasOwnProperty()
を使用して安全に反復できます。
JavaScriptオブジェクトでは、キーと値のペアのコレクションです。 Object.defineProperty()
は、オブジェクトの新しいプロパティを定義し、プロパティの次の属性を設定できる関数です。
<any>
_:キーに関連付けられた値<boolean>
_: writableがtrue
に設定されている場合新しい値を割り当てることにより、プロパティを更新できます。 false
に設定すると、値を変更できません。<boolean>
_: enumerableがtrue
に設定されている場合プロパティは_for..in
_ループを介してアクセスできます。さらに、Object.keys()
で返される列挙可能なプロパティキーは<boolean>
_: configurableがfalse
に設定されている場合、プロパティ属性(value/writable/enumerable/configurable)は変更できません。 delete
演算子を使用して削除することはできません。_let obj = {};
Object.defineProperty(obj, 'prop1', {
value: 1,
writable: false,
enumerable: false,
configurable: false
}); // create a new property (key=prop1, value=1)
Object.defineProperty(obj, 'prop2', {
value: 2,
writable: true,
enumerable: true,
configurable: true
}); // create a new property (key=prop2, value=2)
console.log(obj.prop1, obj.prop2); // both props exists
for(const props in obj) {
console.log(props);
// only logs prop2 because writable is true in prop2 and false in prop1
}
obj.prop1 = 100;
obj.prop2 = 100;
console.log(obj.prop1, obj.prop2);
// only prop2 is changed because prop2 is writable, prop1 is not
delete obj.prop1;
delete obj.prop2;
console.log(obj.prop1, obj.prop2);
// only prop2 is deleted because prop2 is configurable and prop1 is not
_
非常に便利なケースは、何かへの変更を監視し、それに基づいて行動することです。値が設定されるたびにコールバック関数を起動できるため、簡単です。これが基本的な例です。
再生中または再生できないオブジェクトPlayer
があります。再生を開始した直後と、再生を停止した直後に何かが発生したいとします。
function Player(){}
Object.defineProperty(Player.prototype, 'is_playing', {
get(){
return this.stored_is_playing; // note: this.is_playing would result in an endless loop
},
set(newVal){
this.stored_is_playing = newVal;
if (newVal === true) {
showPauseButton();
} else {
showPlayButton();
}
}
});
const cdplayer = new Player();
cdplayer.is_playing = true; // showPauseButton fires
この回答は、他のいくつかの回答に関連しています。これらは詳細情報への適切なステップですが、ライブラリやプログラミングパラダイムについて読むために外部リンクをたどる必要はありません。