Table of contents

  • Objects
  • Prototypes
  • This

JavaScript’s core—most often used and most fundamental—data type is the Object data type. JavaScript has one complex data type, the Object data type, and it has five simple data types: Number, String, Boolean, Undefined, and Null. Note that these simple (primitive) data types are immutable (cannot be changed), while objects are mutable (can be changed).


What is an Object
An object is an unordered list of primitive data types (and sometimes reference data types) that is stored as a series of name-value pairs. Each item in the list is called a property (functions are called methods).

var myFirstObject = {firstName: "Richard", favoriteAuthor: "Conrad"};

Think of an object as a list that contains items, and each item (a property or a method) in the list is stored by a name-value pair. The property names in the example above are firstName and favoriteAuthor. And the values are “Richard” and “Conrad.”

Property names can be a string or a number, but if the property name is a number, it has to be accessed with the bracket notation.

var ageGroup = {30: "Children", 100:"Very Old"};
console.log(ageGroup.30)      // This will throw an error​
console.log(ageGroup["30"]); // Children​
​
​//It is best to avoid using numbers as property names.


Reference Data Type and Primitive Data Types

One of the main differences between reference data type and primitive data types is reference data type’s value is stored as a reference, it is not stored directly on the variable, as a value, as the primitive data types are. For example:

// The primitive data type String is stored as a value​
​var person = "Kobe"; 
​var anotherPerson = person;  // anotherPerson = the value of person​
person = "Bryant";          //  value of person changed​
​
console.log(anotherPerson); // Kobe​
console.log(person);       //  Bryant

It is worth noting that even though we changed person to “Bryant,” the anotherPerson variable still retains the value that person had.

Compare the primitive data saved-as-value demonstrated above with the save-as-reference for objects:

var person = {name: "Kobe"};
​var anotherPerson = person;
person.name = "Bryant";
​
console.log(anotherPerson.name); // Bryant​
console.log(person.name);        // Bryant

n this example, we copied the person object to anotherPerson, but because the value in person was stored as a reference and not an actual value, when we changed the person.name property to “Bryant” the anotherPerson reflected the change because it never stored an actual copy of it’s own value of the person’s properties, it only had a reference to it.


Object Data Properties Have Attributes

Each data property (object property that store data) has not only the name-value pair, but also 3 attributes (the three attributes are set to true by default):

— Configurable Attribute: Specifies whether the property can be deleted or changed.
— Enumerable: Specifies whether the property can be returned in a for/in loop.
— Writable: Specifies whether the property can be changed.

var myObject = {
 a: 2
};

Object.getOwnPropertyDescriptor( myObject, "a" );
// {
// value: 2,
// writable: true,
// enumerable: true,
// configurable: true
// }

As you can see, the property descriptor (called a data descriptor since it’s only for holding a data value) for our normal object property ‘a’ is much more than just its value of 2. It includes 3 other characteristics: writableenumerable, and configurable.

While we can see what the default values for the property descriptor characteristics are when we create a normal property, we can use Object.defineProperty(..) to add a new property or modify an existing one (if it’s configurable !), with the desired characteristics.

var myObject = {};
Object.defineProperty(myObject, "a", {
 value: 2,
 writable: true,
 configurable: true,
 enumerable: true
});
myObject.a; // 2

Using defineProperty(..), we added the plain, normal `a` property to `myObject` in a manually explicit way. However, you generally wouldn’t use this manual approach unless you wanted to modify one of the descriptor characteristics from its normal behavior.


Writable

The ability for you to change the value of a property is controlled by `writable`.

var myObject = {};
Object.defineProperty( myObject, "a", {
 value: 2,
 writable: false,          // not writable!
 configurable: true,
 enumerable: true
});
myObject.a = 3;
console.log(myObject.a);   // 2

As you can see, our modification of the value silently failed. If we try in `strict mode`, we get an error

"use strict";
var myObject = {};
Object.defineProperty( myObject, "a", {
 value: 2,
 writable: false,    // not writable!
 configurable: true,
 enumerable: true
});
myObject.a = 3;      // TypeError

The `TypeError` tells us we cannot change a non-writable property.

Note: We will discuss getters/setters shortly, but briefly, you can observe that writable: false means a value cannot be changed.


Configurable 

As long as a property is currently configurable, we can modify its descriptor definition, using the same defineProperty(..) utility.

var myObject = {
 a: 2
};
myObject.a = 3;
myObject.a; // 3

Object.defineProperty( myObject, "a", {
 value: 4,
 writable: true,
 configurable: false,   // not configurable!
 enumerable: true
} );

myObject.a; // 4
myObject.a = 5;
myObject.a; // 5

Object.defineProperty( myObject, "a", {
 value: 6,
 writable: true,
 configurable: true,
 enumerable: true
} ); // TypeError

Another thing configurable: false prevents is the ability to use the delete operator to remove an existing property.

var myObject = {
 a: 2
};

myObject.a; // 2
delete myObject.a;
myObject.a; // undefined

Object.defineProperty( myObject, "a", {
 value: 2,
 writable: true,
 configurable: false,
 enumerable: true
} );

myObject.a; // 2
delete myObject.a;
myObject.a; // 2

As you can see, the last delete call failed (silently) because we made the `a` property non-configurable.


Enumerable

The final descriptor characteristic we will mention here (there are two others, which we deal with shortly when we discuss getter/setters) is enumerable.

The name probably makes it obvious, but this characteristic controls if a property will show up in certain object-property enumerations, such as the `for..in` loop. Set to `false` to keep it from showing up in such enumerations, even though it’s still completely accessible. Set to `true` to keep it present.


Object Constant

By combining writable: false and configurable: false, you can essentially create a constant (cannot be changed, redefined or deleted) as an object property, like:

var myObject = {};

Object.defineProperty( myObject, "FAVORITE_NUMBER", {
 value: 42,
 writable: false,
 configurable: false
} );

Creating Objects

These are the two common ways to create objects:

  • Object Literals
    The most common and, indeed, the easiest way to create objects is with the object literal described here:
// This is an empty object initialized using the object literal notation​
​var myBooks = {};
​
​// This is an object with 4 items, again using object literal​
​var mango = {
  color: "yellow",
  shape: "round",
  sweetness: 8,
  ​howSweetAmI: function () {
     console.log("Hmm Hmm Good");
  }
}
  • Object Constructor
    The second most common way to create objects is with Object constructor. A constructor is a function used for initializing new objects, and you use the new keyword to call the constructor.
var mango = new Object ();
mango.color = "yellow";
mango.shape= "round";
mango.sweetness = 8;
​
mango.howSweetAmI = function () {
  console.log("Hmm Hmm Good");
}

How to Access Properties on an Object
The two primary ways of accessing properties of an object are with dot notation and bracket notation.

  1. Dot Notation
  2. Brackets Notation

Serialize and Deserialize Objects

To transfer your objects via HTTP or to otherwise convert it to a string, you will need to serialize it (convert it to a string); you can use the JSON.stringify function to serialize your objects. Note that prior to ECMAScript 5, you had to use a popular json2 library (by Douglas Crockford) to get the JSON.stringify function. It is now standardized in ECMAScript 5.

To Deserialize your object (convert it to an object from a string), you use the JSON.parse function from the same json2 library. This function too has been standardized by ECMAScript 5.

JSON.stringify Examples:

var christmasList = {mike:"Book", jason:"sweater", chelsea:"iPad" }
JSON.stringify (christmasList);
​// Prints this string:​
​// "{"mike":"Book","jason":"sweater","chels":"iPad"}"
​
​// To print a stringified object with formatting, 
// add "null" and "4" as parameters:​
JSON.stringify (christmasList, null, 4);
// "{
 "mike": "Book",
 "jason": "sweater",
 "chels": "iPad"​
}"
​
​// JSON.parse Examples \\​
// The following is a JSON string, so we cannot access the properties
// with dot notation (like christmasListStr.mike)​
​var christmasListStr = '{"mike":"Book","jason":"sweater","chels":"iPad"}';
​
​// Let’s convert it to an object​
​var christmasListObj = JSON.parse (christmasListStr); 
​
​// Now that it is an object, we use dot notation​
console.log(christmasListObj.mike); // Book

ProtoTypes and This …..

 

 

Every line of JavaScript code is run in an “execution context.” The JavaScript runtime environment maintains a stack of these contexts, and the top execution context on this stack is the one that’s actively running.

There are three types of executable code: Global code, function code, and eval code. Roughly speaking, global code is code at the top level of your program that’s not inside any functions, function code is code that’s inside the body of a function, and eval code is global code evaluated by a call to eval.

The object that this refers to is redetermined every time control enters a new execution context and remains fixed until control shifts to a different context. The value of this is dependent upon two things: The type of code being executed (i.e., global, function, or eval) and the caller of that code.

The first rule is simple: this refers to the global object in all global code. Since all programs start by executing global code, and this is fixed inside of a given execution context, we know that, by default, this is the global object.

What happens when control shifts to a new execution context? There are only three cases where the value of this changes: method invocations, functions called with the newoperator, and functions called using call and apply. I’ll explain each of these in turn.

Method invocations

If we call a function as a property of an object using either dot (i.e., obj.foo()) or bracket (i.e., obj["foo"]()) notation, this will refer to the parent object in the body of the function:

var info = {                    | var info = {
  name: 'Ahmed',                |    name: 'Ahmed,
  sayName: function (){         |    sayName: function (){
     var name = 'test';         |      var name = 'test;
     return name;               |      return this.name; // return parent
  }                             |    }
};                              | };
console.log(info.sayName()); 
// 'test'                       | console.log(info.sayName()); // 'Ahmed'

This is our second rule: this refers to the parent object inside function code if the function is called as a property of the parent.

The new operator

Any JavaScript function can be used as a constructor function with new. The new operator creates a new object and sets this to the new object inside the function it was called with. For example:

function Employee (name){          | function Employee (name){
  this.name = name;                |   this.name = name;
  this.getName = function (){      |   this.getName = function (){
   var name = 'test';              |    var name = 'test';
   return name;                    |    return this.name;
 };                                |    };
}                                  | }
var emp = new Employee("Ahmed");   | var emp = new Employee("Ahmed");
console.log(emp.getName()); 
// -- 'test'                       | console.log(emp.getName());// Ahmed

another Example:

function F (v) {
  this.val = v;
}
var f = new F("Woohoo!");
console.log(f.val); // Woohoo!
console.log(val);   // ReferenceError

This leads to our third rule: this in function code invoked using the new operator refers to the newly created object.

Note that there’s nothing special about F. If we call it without using new, this will refer to the global object:

var f = F("Oops!");
console.log(f.val); // undefined
console.log(val); // Oops!

In this case, F("Oops!") is a regular function call, and this doesn’t get set to a new object, because no new object is created since the new operator isn’t used. this remains set to the global object.

Call and apply

All JavaScript functions have two methods, call and apply, which let you call functions and explicitly set the value of this. The apply method takes two arguments: an object to set this to, and an (optional) array of arguments to pass to the function:

var add = function (x, y) {
      this.val = x + y;
    },
    obj = {
      val: 0
    };
add.apply(obj, [2, 8]);
console.log(obj.val); // 10

The call method works exactly the same as apply, but you pass the arguments individually rather than in an array:

add.call(obj, 2, 8);
console.log(obj.val); // 10

This is our fourth rule: this is set to the first argument passed to call or apply inside function code when that function is called with either call or apply


Examples:

function foo() {
 console.log( this.a );
}
var obj = {
 a: 2,
 foo: foo
};
var bar = obj.foo;       // function reference/alias!
var a = "oops, global";  // `a` also property on global object.
bar(); // "oops, global" // rule number 1 applied. 


function foo() {
 console.log( this.a );
}
var obj = {
 a: 2,
 foo: foo
};
var a = "oops, global"; // `a` also property on global object
setTimeout( obj.foo, 100 ); // "oops, global"

Think about this crude theoretical pseudo-implementation of 
`setTimeout()` provided as a built-in from the JavaScript environment:
```js
function setTimeout(fn,delay) {
 // wait (somehow) for `delay` milliseconds
 fn(); // <-- call-site!  // rule number one.
}

Summary

That’s it! You can figure out what object this refers to by following a few simple rules:

  • By default, this refers to the global object.
  • When a function is called as a property on a parent object, this refers to the parent object inside that function.
  • When a function is called with the new operator, this refers to the newly created object inside that function.
  • When a function is called using call or apply, this refers to the first argument passed to call or apply. If the first argument is null or not an object, this refers to the global object.

If you understand and follow those four rules, you will always know what this is.


 a: 2
};

("a" in myObject); // true
("b" in myObject); // false

myObject.hasOwnProperty( "a" ); // true
myObject.hasOwnProperty( "b" ); // false

 

 

Advertisements