Object Oriented Javascript: © 2013, Cognizant Technology Solutions
Object Oriented Javascript: © 2013, Cognizant Technology Solutions
Defining Properties
Detecting Properties
Removing Properties
Enumeration
Property Access
Types of Properties
Property Attributes
Preventing Object Modification
Even though there are a number of built in reference types in JavaScript, you will most
likely create your own objects fairly frequently.
objects in JavaScript are dynamic, meaning that they can change at any point during
code execution.
Whereas class-based languages lock down objects based on a class definition,
JavaScript objects have no such restrictions.
Defining Properties
There are two basic ways to create your own objects: using the Object constructor
and using an object literal.
person2.name = “Suman";
person1.age = “234";
person2.age = “111";
person1.name = “Krishna";
person2.name = “Kumar";
Defining Properties
When a property is first added to an object, JavaScript uses an internal method called
[[Put]] on the object.
The [[Put]] method creates a spot in the object to store the property.
The result of calling [[Put]] is the creation of an own property on the object.
An own property simply indicates that the specific instance of the object owns that
property.
When a new value is assigned to an existing property, a separate operation called
[[Set]] takes place.
This operation replaces the current value of the property with the new one.
Detecting Properties
Because properties can be added at any time, it’s sometimes necessary to check
whether a property exists in the object.
JavaScript developers often incorrectly use patterns like the following to detect
whether a property exists:
// unreliable
if (person1.age) {
// do something with age
}
The problem with this pattern is how JavaScript’s type coercion affects the outcome.
The if condition evaluates to true if the value is truthy (an object, a nonempty string,
a nonzero number, or true) and evaluates to false if the value is falsy (null, undefined,
0, false, NaN, or an empty string).
Detecting Properties
Because an object property can contain one of these falsy values, the example code
can yield false negatives.
For instance, if person1.age is 0, then the if condition will not be met even though the
property exists.
A more reliable way to test for the existence of a property is with the in operator
The in operator looks for a property with a given name in a specific object and returns
true if it finds it
console.log("name" in person1); // true
console.log("age" in person1); // true
console.log("title" in person1); // false
Detecting Properties
Keep in mind that methods are just properties that reference functions, so you can
check for the existence of a method in the same way.
The following adds a new function, sayName(), to person1 and uses in to confirm the
function’s presence.
var person1 = {
name: “Suman",
sayName: function() {
console.log(this.name);
}
};
console.log("sayName" in person1); // true
In most cases, the in operator is the best way to determine whether the property
exists in an object.
Detecting Properties
It has the added benefit of not evaluating the value of the property, which can be
important if such an evaluation is likely to cause a performance issue or an error.
In some cases, however, you might want to check for the existence of a property only
if it is an own property.
The in operator checks for both own properties and prototype properties.
We have hasOwnProperty() method, which is present on all objects and returns true
only if the given property exists and is an own property.
For example, the following code compares the results of using in versus
hasOwnProperty() on different properties in person1:
Detecting Properties
var person1 = {
name: "Nicholas",
sayName: function() {
console.log(this.name);
} };
The toString() method, however, is a prototype property that is present on all objects.
Removing Properties
Just as properties can be added to objects at any time, they can also be removed.
Simply setting a property to null doesn’t actually remove the property completely
from the object.
Such an operation calls [[Set]] with a value of null, which you saw earlier in the
session, only replaces the value of the property.
You need to use the delete operator to completely remove a property from an object.
The delete operator works on a single object property and calls an internal operation
named [[Delete]].
When the delete operator is successful, it returns true.
Removing Properties
var person1 = {
name: “Suman"
};
console.log("name" in person1); // true
delete person1.name; // true
console.log("name" in person1); // false
console.log(person1.name); // undefined
Enumeration
By default, all properties that you add to an object are enumerable, which means that
you can iterate over them using a for-in loop.
Enumerable properties have their internal [[Enumerable]] attributes set to true.
var property;
for (property in object)
{
console.log("Name: " + property);
console.log("Value: " + object[property]);
}
Each time through the for-in loop, the property variable is filled with the next
enumerable property on the object until all such properties have been used.
Enumeration
If you just need a list of an object’s properties to use later in your program, ECMAScript
5 introduced the Object.keys() method to retrieve an array of enumerable property
names
var properties = Object.keys(object);
// if you want to mimic for-in behavior
var i, len;
for (i=0, len=properties.length; i < len; i++){
console.log("Name: " + properties[i]);
console.log("Value: " + object[properties[i]]);
}
Typically, you would use Object.keys() in situations where you want to operate on an
array of property names and for-in when you don’t need an array.
Enumeration
Keep in mind that not all properties are enumerable. In fact, most of the native
methods on objects have their [[Enumerable]] attribute set to false.
Types of Properties
There are two different types of properties: data properties and accessor properties.
Data properties contain a value, like the name property from earlier examples
Accessor properties don’t contain a value but instead define a function to call when the
property is read (called a getter), and a function to call when the property is written to
(called a setter).
Accessor properties only require either a getter or a setter, though they can have both.
Types of Properties
var person1 = {
_name: “Suman",
get name() {
console.log("Reading name");
return this._name;
},
set name(value) {
console.log("Setting name to %s", value);
this._name = value; }
};
console.log(person1.name); // "Reading name" then “Suman"
person1.name = “Mishra";
console.log(person1.name); // "Setting name to Mishra" then “Mishra"
Types of Properties
Property Attributes
There are two property attributes shared between data and accessor properties.
One is [[Enumerable]], which determines whether you can iterate over the property.
Property Attributes
By default, all properties you declare on an object are both enumerable and
configurable.
If you want to change property attributes, you can use the Object.defineProperty()
method.
This method accepts three arguments: the object that owns the property, the property
name, and a property descriptor object containing the attributes to set.
The descriptor has properties with the same name as the internal attributes but
without the square brackets.
Property Attributes
For example, suppose you want to make an object property nonenumerable and
nonconfigurable:
var person1 = {
name: “Suman“
};
Object.defineProperty(person1, "name", { enumerable: false });
Property Attributes
delete person1.name;
When JavaScript is running in strict mode, attempting to delete a nonconfigurable property
results in an error. In nonstrict mode, the operation silently fails.
console.log("name" in person1); // true
console.log(person1.name); // “Suman"
You’ve seen this snippet throughout this session; it adds the name property to person1
and sets its value. You can achieve the same result using the following (more verbose)
code
var person1 = {};
Object.defineProperty(person1, "name", {
value: “Suman",
enumerable: true,
configurable: true,
writable: true
});
When you are defining a new property with Object.defineProperty(), it’s important to
specify all of the attributes because Boolean attributes automatically default to false
otherwise.
For example, the following code creates a name property that is nonenumerable,
nonconfigurable, and nonwritable because it doesn’t explicitly make any of those
attributes true in the call to Object.defineProperty().
delete person1.name;
person1.name = "Greg";
Nonwritable properties throw an error in strict mode when you try to
change the value. In nonstrict mode, the operation silently fails.
console.log(person1.name); // “Suman"
var person1 = {
_name: “Suman",
get name() {
console.log("Reading name"); return
this._name;
},
set name(value) {
console.log("Setting name to ", value);
this._name = value;
}
};
It’s also possible to define multiple properties on an object simultaneously if you use
Object.defineProperties() instead of Object.defineProperty().
This method accepts two arguments: the object to work on and an object containing
all of the property information.
The keys of that second argument are property names, and the values are descriptor
objects defining the attributes for those properties.
This method accepts two arguments: the object to work on and the property name to
retrieve.
If the property exists, you should receive a descriptor object with four properties:
configurable, enumerable, and the two others appropriate for the type of property.
For example, this code creates a property and checks its attributes:
console.log(descriptor.enumerable); // true
console.log(descriptor.configurable); // true
console.log(descriptor.writable); // true
console.log(descriptor.value); // “Suman"
Objects, just like properties, have internal attributes that govern their behavior.
Preventing Extensions
This method accepts a single argument, which is the object you want to make
nonextensible.
Once you use this method on an object, you’ll never be able to add any new
properties to it again.
You can check the value of [[Extensible]] by using Object.isExtensible().
Preventing Extensions
console.log(Object.isExtensible(person1)); // true
Object.preventExtensions(person1);
console.log(Object.isExtensible(person1)); // false
person1.sayName = function() {
console.log(this.name);
};
Sealing Objects
That means not only can you not add new properties to the object, but you also
can’t remove properties
You can use the Object.seal() method on an object to seal it.
When that happens, the [[Extensible]] attribute is set to false, and all properties
have their [[Configurable]] attribute set to false.
Constructors
Prototypes