65.9K
CodeProject is changing. Read more.
Home

How to JavaScript - Using defineProperty() and defineProperties()

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.38/5 (4 votes)

Oct 16, 2017

CPOL

2 min read

viewsIcon

8990

JavaScript Design patterns - The Constructor Pattern

Introduction

In this article, I would like to explain how to use Object.defineProperty() and Object.defineProperties() methods. These two methods define new or modify existing properties directly on an object, returning the object (Visit MDN, which has an excellent introduction to them).

Creating an Object

If you consider an OOP JavaScript world, almost everything is an object. When it comes to object creation, I used to use one of the following three methods:

var beautifulObject = {};

// OR
var beautifulObject = Object.create( Object.prototype );

//OR
var beautifulObject = new Object();

Defining Object Property

Interestingly, there are four ways to assign keys and values to the object.

  1. Dot Syntax
  2. Square Bracket Syntax
  3. Object.defineProperty()
  4. Object.defineProperties()

A simple example of Dot syntax and Square Bracket syntax for assigning and accessing the object property:

// Dot Syntax
// Assignment
beautifulObject.beautifulProperty = "It is a beautiful property";
// Accessing
var prop = beautifulObject.beautifulProperty;

// Square Bracket syntax
// Assignment
beautifulObject["beautifulProperty"] = "It is a beautiful property";
// Accessing
var prop = beautifulObject["beautifulProperty"];

In the above examples, we do not control the property descriptor. That means it uses the default descriptor behaviour. Object property can be writable, re-configurable and enumerable. If we need control over all these, then we need to define the property using defineProperty() or defineProperties().

A simple example for defining object property with defineProperty():

var person = new Object(Object.prototype);

Object.defineProperty(person, "beautifulProperty", {
    value :  "It is a beautiful property",
    writable : false,    // readonly
    enumerable : false,  // not enumerable property
    configurable : false // do not allow re-configure the peroperty
});

console.log(person); 
// logs {beautifulProperty : "It is a beautiful property"}

When we want to define multiple properties with the descriptor, then we need to use defineProperties():

var person = new Object(Object.prototype); 
var country = "India";

Object.defineProperties(person, {
    "gender" : {
        value : "male",
        writable : true,
        enumerable : true,
        configurable : false
    },
    "name" : {
        value : "Vinnie",
        writable : true,
        enumerable : true,
        configurable : false
    },
    "dob" : {
        value : "dd-MMM-YYYY",
        writable : true,
        enumerable : true,
        configurable : false
    },
    "country" : {
        // Lets user get/set accessors here
        // Please note using value and writable descriptor throws error when get/set is used 
        enumerable : true,
        get : function () {
            return country;
        },
        set : function (newCountry) {
            country = newCountry;
        }
    }
});

console.log(person);
// logs {gender: "male", name:"Vinnie", dob:"dd-MMM-YYYY", Country: [Getter/Setter]}

Now you might be wondering what is the use case of this design pattern. Well, with this constructor design pattern, it is very easy to achieve inheritance.

Say, I have a person object created above. If we need to create an object called a programmer and inherit the person properties, we can achieve like below:

var programmer = Object.create(person);
Object.defineProperty(programmer, "competency", {
    value : "JavaScript",
    writable : true,
    enumerable : true,
    configurable : true
});

console.log(programmer );
// logs {gender: "male", name:"Vinnie", dob:"dd-MMM-YYYY", 
// Country: [Getter/Setter], competency:"JavaScript"}

The programmer object inherits all the properties of the person.

Conclusion

Whenever we need to make an object property to be read-only or non-enumerable, Object.defineProperty() is very useful. With the enumerable descriptor, an object can, in some ways, simulate pseudo-private fields. Inheritance concept becomes painless.

References and Learning

History

  • 2017-Oct-14: First published