Additional examples for Object.defineProperty

この翻訳は不完全です。英語から この記事を翻訳 してください。

このページでは、Object.defineProperty() の追加の使用例を提供します。

プロパティ記述子オブジェクトの代わりにバイナリフラグを使用する

Object.defineProperty() メソッドを通して多くのプロパティを定義する必要がある場合、各プロパティに対して同じ記述子オブジェクトを使用し、binary flags を通して随時それを再定義してください。

var oDesc = {};
function setProp (nMask, oObj, sKey, vVal_fGet, fSet) {
  if (nMask & 8) {
    // accessor descriptor
    if (vVal_fGet) {
      oDesc.get = vVal_fGet;
    } else {
      delete oDesc.get;
    }
    if (fSet) {
      oDesc.set = fSet;
    } else {
      delete oDesc.set;
    }
    delete oDesc.value;
    delete oDesc.writable;
  } else {
    // data descriptor
    if (arguments.length > 3) {
      oDesc.value = vVal_fGet;
    } else {
      delete oDesc.value;
    }
    oDesc.writable = Boolean(nMask & 4);
    delete oDesc.get;
    delete oDesc.set;
  }
  oDesc.enumerable = Boolean(nMask & 1);
  oDesc.configurable = Boolean(nMask & 2);
  Object.defineProperty(oObj, sKey, oDesc);
  return oObj;
}

/*
* :: function setProp ::
*
* nMask is a bitmask:
*  flag 0x1: property is enumerable,
*  flag 0x2: property is configurable,
*  flag 0x4: property is writable,
*  flag 0x8: property is accessor descriptor.
* oObj is the object on which to define the property;
* sKey is the name of the property to be defined or modified;
* vVal_fGet is the value to assign to a data descriptor or the getter function
* to assign to an accessor descriptor (depending on the bitmask);
* fSet is the setter function to assign to an accessor descriptor;
*
* Bitmask possible values:
*
*  0  : readonly data descriptor - not configurable, not enumerable (0000).
*  1  : readonly data descriptor - not configurable, enumerable (0001).
*  2  : readonly data descriptor - configurable, not enumerable (0010).
*  3  : readonly data descriptor - configurable, enumerable (0011).
*  4  : writable data descriptor - not configurable, not enumerable (0100).
*  5  : writable data descriptor - not configurable, enumerable (0101).
*  6  : writable data descriptor - configurable, not enumerable (0110).
*  7  : writable data descriptor - configurable, enumerable (0111).
*  8  : accessor descriptor - not configurable, not enumerable (1000).
*  9  : accessor descriptor - not configurable, enumerable (1001).
*  10 : accessor descriptor - configurable, not enumerable (1010).
*  11 : accessor descriptor - configurable, enumerable (1011).
*
*  Note: If the flag 0x8 is setted to "accessor descriptor" the flag 0x4 (writable)
*  will be ignored. If not, the fSet argument will be ignored.
*/

// creating a new empty object
var myObj = {};

// adding a writable data descriptor - not configurable, not enumerable
setProp(4, myObj, 'myNumber', 25);

// adding a readonly data descriptor - not configurable, enumerable
setProp(1, myObj, 'myString', 'Hello world!');

// adding an accessor descriptor - not configurable, enumerable
setProp(9, myObj, 'myArray', function() {
  for (var iBit = 0, iFlag = 1, aBoolArr = [false];
    iFlag < this.myNumber + 1 || (this.myNumber & iFlag);
    iFlag = iFlag << 1
  ) {
    aBoolArr[iBit++] = Boolean(this.myNumber & iFlag);
  }
  return aBoolArr;
}, function(aNewMask) {
  for (var nNew = 0, iBit = 0; iBit < aNewMask.length; iBit++) {
    nNew |= Boolean(aNewMask[iBit]) << iBit;
  }
  this.myNumber = nNew;
});

// adding a writable data descriptor (undefined value) - configurable, enumerable
setProp(7, myObj, 'myUndefined');

// adding an accessor descriptor (only getter) - configurable, enumerable
setProp(11, myObj, 'myDate', function() { return new Date(); });

// adding an accessor descriptor (only setter) - not configurable, not enumerable
setProp(8, myObj, 'myAlert', null, function(sTxt) { alert(sTxt); });

myObj.myAlert = myObj.myDate.toLocaleString() + '\n\n' + myObj.myString +
  '\nThe number ' + myObj.myNumber + ' represents the following bitmask: ' +
  myObj.myArray.join(', ') + '.';

// listing the enumerable properties
var sList = 'Here are the enumerable properties of myObj object:\n';
for (var sProp in myObj) {
  sList += '\nmyObj.' + sProp + ' => ' + myObj[sProp] + ';'
}

alert(sList);

新しい非ネイティブ Object.setProperty() メソッドを生成する

匿名のコンストラクタと ObjectsetProperty() という名前のカスタムメソッドを通して取得した記述子オブジェクトにより同じことができます:

// creating a new Object method named Object.setProperty()

new (function() {
  var oDesc = this;
  Object.setProperty = function(nMask, oObj, sKey, vVal_fGet, fSet) {
    if (nMask & 8) {
      // accessor descriptor
      if (vVal_fGet) {
        oDesc.get = vVal_fGet;
      } else {
        delete oDesc.get;
      }
      if (fSet) {
        oDesc.set = fSet;
      } else {
        delete oDesc.set;
      }
      delete oDesc.value;
      delete oDesc.writable;
    } else {
      // data descriptor
      if (arguments.length > 3) {
        oDesc.value = vVal_fGet;
      } else {
        delete oDesc.value;
      }
      oDesc.writable = Boolean(nMask & 4);
      delete oDesc.get;
      delete oDesc.set;
    }
    oDesc.enumerable = Boolean(nMask & 1);
    oDesc.configurable = Boolean(nMask & 2);
    Object.defineProperty(oObj, sKey, oDesc);
    return oObj;
  };
})();

// creating a new empty object
var myObj = {};

// adding a writable data descriptor - not configurable, not enumerable
Object.setProperty(4, myObj, 'myNumber', 25);

// adding a readonly data descriptor - not configurable, enumerable
Object.setProperty(1, myObj, 'myString', 'Hello world!');

// etc. etc.
注記: Object.setProperty() メソッドも JavaScript の新しいネイティブメソッドとして提案される可能性があります (ECMAScript bug 335 を参照)。

構文

Object.setProperty(bitmask, obj, prop[, value/getter[, setter]])

引数

bitmask
記述子ビットマスク (下記参照)。
obj
プロパティが定義されるオブジェクト。
prop
定義または修正されるプロパティの名前。
value/getter
任意。データ記述子に割り当てる値、または、(ビットマスクに依存した) アクセサ記述子に割り当てる getter 関数 (bitmask に依存)。
setter
任意。アクセサ記述子に割り当てる setter 関数。フラグ 0x8データ記述子 に設定されている場合、この引数は無視されます。

説明

非ネイティブの Object.setProperty() メソッドは、記述子ビットマスクで置き換えられた記述子オブジェクトに対するもの除き、ネイティブの Object.defineProperty() メソッドのように動作します。bitmask 引数は次の構造を持ちます:

flag 0x1
プロパティは列挙可です。
flag 0x2
プロパティは設定可です。
flag 0x4
プロパティは書込可です。
flag 0x8
プロパティはアクセサ記述子です。

そのため、記述子ビットマスクは下記の可能な数値を持ちます:

  • 0: 読取専用の データ 記述子を表します。設定不可、列挙不可 (0000)
  • 1: 読取専用の データ 記述子を表します。設定不可、列挙可 (0001)
  • 2: 読取専用の データ 記述子を表します。設定可、列挙不可 (0010)
  • 3: 読取専用の データ 記述子を表します。設定可、列挙可 (0011)
  • 4: 書込可能な データ 記述子を表します。設定不可、列挙不可 (0100)
  • 5: 書込可能な データ 記述子を表します。設定不可、列挙可 (0101).
  • 6: 書込可能な データ 記述子を表します。設定可、列挙不可 (0110).
  • 7: 書込可能な データ 記述子を表します。設定可、列挙可 (0111).
  • 8: アクセサ 記述子を表します。設定不可、列挙不可 (1000).
  • 9: アクセサ 記述子を表します。設定不可、列挙可 (1001).
  • 10: アクセサ 記述子を表します。設定可、列挙不可 (1010).
  • 11: アクセサ 記述子を表します。設定可、列挙可 (1011).
注記: フラグ 0x8アクセサ記述子 に設定されている場合、フラグ 0x4 (書込可能) は無視されます。設定されていない場合、setter 引数は無視されます。

HTMLSelectElement.selectedIndex 実装

ネイティブオブジェクトとともに Object.defineProperty() メソッドを使用することもできます。次の例では、ラジオボタングループで HTMLSelectElementselectedIndex を実装する方法を示します。

<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Radio group selectedIndex example</title>
<script type="text/javascript">
Object.defineProperty(NodeList.prototype, 'selectedIndex', {
  get: function() {
    var nIndex = this.length - 1;
    while (nIndex > -1 && !this[nIndex].checked) {
      nIndex--;
    }
    return nIndex;
  },

  set: function(nNewIndex) {
    if (isNaN(nNewIndex)) {
      return;
    }
    var nOldIndex = this.selectedIndex;
    if (nOldIndex > -1) {
      this[nOldIndex].checked = false;
    }
    if (nNewIndex > -1) {
      this[nNewIndex].checked = true;
    }
  },

  enumerable: true,
  configurable: false
});

// try it!
function checkForm() {
  var nSelectedIndex = document.myForm.myRadioGroup.selectedIndex;
  if (nSelectedIndex < 0) {
    alert('Select a gadget!!');
    return false;
  }
  alert('Congratulations!! You selected the ' + document.myForm.myRadioGroup[nSelectedIndex].value + '.');
  return true;
}
</script>
</head>

<body>
  <form name="myForm" onsubmit="return(checkForm());">
    <fieldset><legend>Select a gadget</legend>
      <p><input type="radio" name="myRadioGroup" id="ourShirt" value="shirt" /> <label for="ourShirt">shirt</label><br />
      <input type="radio" name="myRadioGroup" id="ourPants" value="pants" /> <label for="ourPants">pants</label><br />
      <input type="radio" name="myRadioGroup" id="ourBelt" value="belt" /> <label for="ourBelt">belt</label><br />
      <input type="radio" name="myRadioGroup" id="ourShoes" value="shoes" /> <label for="ourShoes">shoes</label></p>
      <p><span style="cursor:pointer;text-decoration:underline;color:#0000ff;" onclick="document.myForm.myRadioGroup.selectedIndex=2;">Select our favorite gadget ;-)</span></p>
      <p><input type="submit" value="Order!" />
    </fieldset>
  </form>
</body>
</html>

ドキュメントのタグと貢献者

 このページの貢献者: Marsf, shide55
 最終更新者: Marsf,