web-dev-qa-db-ja.com

いつObject.defineProperty()を使用しますか

いつ使うべきか迷っています

Object.defineProperty

オブジェクトの新しいプロパティを作成します。私は次のようなものを設定できることを知っています

enumerable: false

しかし、これが本当に必要なのはいつですか?あなただけのようなプロパティを設定した場合

myObject.myprop = 5;

その記述子はすべてtrueに設定されていますよね?皆さんが.defineProperty()へのかなり冗長な呼び出しを使用するとき、そしてその理由について、私は実際にもっと興味があります。

65
Andre Meinhold

_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]"
_
38
Rob W

「列挙可能」などの機能は、私の経験ではほとんど使用されていません。主なユースケースは計算されたプロパティです:

var myObj = {};

myObj.width = 20;
myObj.height = 20;

Object.defineProperty(myObj, 'area', {
    get: function() {
        return this.width*this.height;
    }
});
console.log(myObj.area);
22
Pascalius

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に設定してください。

12
Gerard Simpson

たとえば、 Vue.jsがdataオブジェクトの変更を追跡しているものです

プレーンJavaScriptオブジェクトをVueインスタンスとしてdataオプションとして渡すと、Vueはすべてのプロパティをウォークスルーして変換しますgetter/settersを使用してObject.definePropertyに変換します。これはES5のみでシムできない機能であるため、VueはIE8以下をサポートしていません。

ゲッター/セッターはユーザーには見えませんが、内部ではVueを有効にして、プロパティがアクセスまたは変更されたときに依存関係の追跡と変更通知を実行できます。

[...]

Vue.jsの非常にスリムでベーシックなバージョンでもObject.defineProperty以外のものも使用しますが、主な機能は次のとおりです。

Vue.js's Reactivity Cycle

ここでは、著者が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

2
Danziger

私が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;
    },
  });

このコードのソース: https://github.com/apollographql/react-apollo/blob/ddd3d8faabf135dca691d20ce8ab0bc24ccc414e/src/graphql.tsx#L51

2
Alfonso Pérez

良い使い方は、インターセプトを行う必要がある場合や、古典的なObserver/Observableパターンをエレガントな方法で適用する必要がある場合です。

https://www.monterail.com/blog/2016/how-to-build-a-reactive-engine-in-javascript-part-1-observable-objects

1
David

_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()を使用して安全に反復できます。

1
Anish Choudhary

概要:

JavaScriptオブジェクトでは、キーと値のペアのコレクションです。 Object.defineProperty()は、オブジェクトの新しいプロパティを定義し、プロパティの次の属性を設定できる関数です。

  • 値_<any>_:キーに関連付けられた値
  • writable _<boolean>_: writableがtrueに設定されている場合新しい値を割り当てることにより、プロパティを更新できます。 falseに設定すると、値を変更できません。
  • enumerable _<boolean>_: enumerableがtrueに設定されている場合プロパティは_for..in_ループを介してアクセスできます。さらに、Object.keys()で返される列挙可能なプロパティキーは
  • configurable _<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_
1

非常に便利なケースは、何かへの変更を監視し、それに基づいて行動することです。値が設定されるたびにコールバック関数を起動できるため、簡単です。これが基本的な例です。

再生中または再生できないオブジェクト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 

この回答は、他のいくつかの回答に関連しています。これらは詳細情報への適切なステップですが、ライブラリやプログラミングパラダイムについて読むために外部リンクをたどる必要はありません。

0
AFOC