mozilla
Your Search Results

    Additional examples for Object.defineProperty

    This page provides additional examples for Object.defineProperty().

    Using binary flags instead of a property descriptor object

    If you have to define many properties through the Object.defineProperty() method, you can use the same descriptor object for each property, redefining it from time to time through 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);
    

    Create a new non-native Object.setProperty() method

    You can do the same thing with a descriptor object obtained through an anonymous constructor and an Object's custom method named 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.
    
    Note: The Object.setProperty() method could be also a proposal for a possible new JavaScript native method (see ECMAScript bug 335).

    Syntax

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

    Parameters

    bitmask
    The descriptor bitmask (see below).
    obj
    The object on which to define the property.
    prop
    The name of the property to be defined or modified.
    value/getter
    Optional. The value to assign to a data descriptor or the getter function to assign to an accessor descriptor (depends on the bitmask).
    setter
    Optional. The setter function to assign to an accessor descriptor. If the flag 0x8 is setted to data descriptor this argument will be ignored.

    Description

    The non-native Object.setProperty() method works like the native Object.defineProperty() method, except for the descriptor object which is replaced with a descriptor bitmask. The bitmask argument has the following structure:

    flag 0x1
    The property is enumerable.
    flag 0x2
    The property is configurable.
    flag 0x4
    The property is writable.
    flag 0x8
    The property is an accessor descriptor.

    So, the descriptor bitmask can have these possible numeric values:

    • 0: The bitmask represents a readonly data descriptor — not configurable, not enumerable (0000).
    • 1: The bitmask represents a readonly data descriptor — not configurable, enumerable (0001).
    • 2: The bitmask represents a readonly data descriptor — configurable, not enumerable (0010).
    • 3: The bitmask represents a readonly data descriptor — configurable, enumerable (0011).
    • 4: The bitmask represents a writable data descriptor — not configurable, not enumerable (0100).
    • 5: The bitmask represents a writable data descriptor — not configurable, enumerable (0101).
    • 6: The bitmask represents a writable data descriptor — configurable, not enumerable (0110).
    • 7: The bitmask represents a writable data descriptor — configurable, enumerable (0111).
    • 8: The bitmask represents an accessor descriptor — not configurable, not enumerable (1000).
    • 9: The bitmask represents an accessor descriptor — not configurable, enumerable (1001).
    • 10: The bitmask represents an accessor descriptor — configurable, not enumerable (1010).
    • 11: The bitmask represents an accessor descriptor — configurable, enumerable (1011).
    Note: If the flag 0x8 is set to accessor descriptor the flag 0x4 (writable) will be ignored. If not, the setter argument will be ignored.

    HTMLSelectElement.selectedIndex implementation

    You can use the Object.defineProperty() method with native objects also. The following example shows how to implement the HTMLSelectElement's selectedIndex property in radio button groups.

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

    Document Tags and Contributors

    Contributors to this page: Sheppy, royling, fscholz, rober7106tn6, dbruant, Mingun, rsneekes, fusionchess
    Last updated by: fscholz,