本页为`Object.defineProperty()`提供一个附加示例。

## 使用二进制标志代替属性来描述对象

如果你通过`Object.defineProperty()`方法定义了许多属性，你可以通过`二进制标志`使用相同的描述对象，一次次重新定义每个属性。

    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()` 方法

你可以对通过匿名构造函数和`Object`的名为`setProperty()`的自定义方法获取的描述符对象做同样的事情：

    // 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函数（取决于位掩码）。
`setter`
  可选。setter 函数将分配到可访问描述符。如果`0x8`标识已经设置， 这个参数将会被忽略。

### 描述

除了用描述符位掩码替换的描述符对象外，非原生`Object.setProperty()`方法与原生`Object.defineProperty()`方法类似。 `bitmask`参数具有以下结构：

flag `0x1`
  属性可枚举。
flag `0x2`
  属性可配置。
flag `0x4`
  属性可写入。
flag `0x8`
  属性为可访问描述符（其实就是一个 key: function）

所以，描述位掩码可以有以下可能的值：

- `0`: 位掩码表示只读数据描述符 — not configurable, not enumerable (`0000`).
- `1`: 位掩码表示只读数据描述符 — not configurable, enumerable (`0001`).
- `2`: 位掩码表示只读数据描述符 — configurable, not enumerable (`0010`).
- `3`: 位掩码表示只读数据描述符 — configurable, enumerable (`0011`).
- `4`: 位掩码表示可写数据描述符 — not configurable, not enumerable (`0100`).
- `5`: 位掩码表示可写数据描述符 — not configurable, enumerable (`0101`).
- `6`: T位掩码表示可写数据描述符 — configurable, not enumerable (`0110`).
- `7`: T位掩码表示可写数据描述符 — configurable, enumerable (`0111`).
- `8`: 位掩码表示可访问数据描述符 — not configurable, not enumerable (`1000`).
- `9`: 位掩码表示可访问数据描述符 — not configurable, enumerable (`1001`).
- `10`: 位掩码表示可访问数据描述符 — configurable, not enumerable (`1010`).
- `11`: 位掩码表示可访问数据描述符 — configurable, enumerable (`1011`).

注意：如果标志`0x8`被设置为访问描述符，则标志`0x4`（可写）将被忽略。否则，`setter`参数将被忽略。

## HTMLSelectElement.selectedIndex 实现

你也可以使用本地方法 `Object.defineProperty()`。用以下例子展现如何实现`HTMLSelectElement` 和 `selectedIndex`单选框组属性。

    <!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>