Table of contents

  • Objects
  • This
  • Prototype
  • __proto__ vs prototype

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.

Prototype

Every object is linked to a prototype object from which it can inherit properties. All objects created from object literals are linked to Object.prototype, an object that comes standard with JavaScript

When you make a new object, you can select the object that should be its prototype.

We will use a create method. The create method creates a new object that uses an old object as its prototype.

The prototype link has no effect on updating. When we make changes to an object, the object’s prototype is not touched.

The prototype link is used only in retrieval. If we try to retrieve a property value from an object, and if the object lacks the property name, then JavaScript attempts to retrieve the property value from the prototype object. And if that object is lacking the property, then it goes to its prototype, and so on until the process finally bottoms out with Object.prototype. If the desired property exists nowhere in the prototype chain, then the result is the undefined value. This is called delegation.

The prototype relationship is a dynamic relationship. If we add a new property to a prototype, that property will immediately be visible in all of the objects that are based on that prototype.

var ahmedInfo = { name: "Ahmed", age: 25, address: "Cairo" };
var yehiaInfo = Object.create(ahmedInfo);
yehiaInfo.name = "Yehia"; 
ahmedInfo.email = "foo.com";
console.log(yehiaInfo.name); // Yehia 
console.log(ahmedInfo.name); // Ahmed
console.log(yehiaInfo.email); // foo.com "from the parent's prototype.

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
} );

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

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, the global code is code at the top level of your program that’s not inside any functions, the 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:

  1. method invocations
  2. functions called with the newoperator
  3. functions called using call and apply

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"
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 thisis


Prototype

The prototype property is used primarily for inheritance; you add methods and properties on a function’s prototype property to make those methods and properties available to instances of that function.

function PrintStuff (myDocuments) {
​  this.documents = myDocuments;
}
​// We add the print () method to PrintStuff prototype property
// so that other instances (objects) can inherit it
​PrintStuff.prototype.print = function () {
console.log(this.documents);
}
​
​// Create a new object with the PrintStuff () constructor
// thus allowing this new object to inherit PrintStuff's 
// properties and methods
.​
​var newObj = new PrintStuff ("I am a new Object and I can print.");
​
​// newObj inherited all the properties and methods
// including the print method, from the PrintStuff function. 
// Now newObj can call print directly, even though we never created 
// a print () method on it.​

newObj.print (); //I am a new Object and I can print.

another Example.. 

​function Employee() {
}
Employee.prototype.sayHello = function () {
  console.log("Hello " + this.role);
}
function Sales() {
  this.role = "sales !";
  this.hasCare = true;
}
Sales.prototype = Employee.prototype;
var emp = new Sales();
console.log(emp.role);
emp.sayHello();

Constructor
Before we continue, let’s briefly examine the constructor. A constructor is a function used for initializing new objects, and you use the new keyword to call the constructor.

function Account () {
}
​// This is the use of the Account constructor 
// to create the userAccount object.​
​var userAccount = new Account ();

Moreover, all objects that inherit from another object also inherit a constructor property. And this constructor property is simply a property (like any variable) that holds or points to the constructor of the object.

// The constructor in this example is Object () ​
​ var myObj = new Object ();
​// And if you later want to find the myObj constructor:​
console.log(myObj.constructor);        // Object()​
​
​// Another example: Account () is the constructor​
​ var userAccount = new Account (); 
​// Find the userAccount object's constructor​
console.log(userAccount.constructor); // Account()
Prototype Attribute of Objects Created with new Object () or Object Literal
All objects created with object literals and with the Object constructor inherits from Object.prototype. Therefore, Object.prototype is the prototype attribute (or the prototype object) of all objects created with new Object () or with {}. Object.prototypeitself does not inherit any methods or properties from any other object.
// The userAccount object inherits from Object and as such its prototype
// attribute is Object.prototype.​​var userAccount = new Object ();​// This demonstrates the use of an object literal
// to create the userAccount object;
// the userAccount object inherits from Object;
// therefore, its prototype attribute is Object.prototype 
// just as the userAccount object does above.​var userAccount = {name: “Mike”}

Prototype Attribute of Objects Created With a Constructor Function

Objects created with the new keyword and any constructor other than the Object () constructor, get their prototype from the constructor function.

For Example:

function Account () {
​
}
​var userAccount = new Account () 
// userAccount initialized with the Account () constructor 
// and as such its prototype attribute (or prototype object) 
// is Account.prototype.

Similarlyany array such as var myArray = new Array (), gets its prototype from Array.prototype and it inherits Array.prototype’s properties.

How new keyword does under the hood !! we can implement our new function just to understand how new keyword works..

/*
Steps
-----------
1- Create a new object..
2- set the protoType.
3- execute constructor with 'This'.
4- return the created object.
*/

function Person(saying) {
  this.saying = saying;
}
Person.prototype.talk = function () {
console.log('I say: ', this.saying);
}

function spawn(constructor) {
  var obj = {};
  Object.setPrototypeOf(obj, constructor.prototype);
  var argsArray = Array.prototype.slice.apply(arguments);
  constructor.apply(obj, argsArray.slice(1));
  return obj;
}
var crockford = spawn(Person, 'SEMICOLANS !!!!');
crockford.talk();  // I say SEMICOLANS !!!!

Why is Prototype Important and When is it Used?
These are two important ways the prototype is used in JavaScript, as we noted above:

  1. Prototype Property: Prototype-based Inheritance
  2. Prototype Attribute: Accessing Properties on Objects

Prototype Property: Prototype-based Inheritance

Prototype is important in JavaScript because JavaScript does not have classical inheritance based on Classes (as most object-oriented languages do), and therefore all inheritance in JavaScript is made possible through the prototype property. JavaScript has a prototype-based inheritance mechanism.Inheritance is a programming paradigm where objects (or Classes in some languages) can inherit properties and methods from other objects (or Classes). In JavaScript, you implement inheritance with the prototype property. For example, you can create a Fruit function (an object, since all functions in JavaScript are objects) and add properties and methods on the Fruit prototype property, and all instances of the Fruit function will inherit all the Fruit’s properties and methods.

Demonstration of Inheritance in JavaScript:

function Plant () {
​this.country = "Mexico";
​this.isOrganic = true;
}
​
​// Add the showNameAndColor method to the Plant prototype property​
Plant.prototype.showNameAndColor = function () {
console.log("I am a " + this.name + " and my color is " + this.color);
}
​
​// Add the amIOrganic method to the Plant prototype property​
Plant.prototype.amIOrganic = function () {
​if (this.isOrganic)
console.log("I am organic, Baby!");
}
​
​function Fruit (fruitName, fruitColor) {
​this.name = fruitName;
​this.color = fruitColor;
}
​
​// Set the Fruit's prototype to Plant's constructor
// thus inheriting all of Plant.prototype methods and properties.​
Fruit.prototype = new Plant ();
​
​// Creates a new object, aBanana, with the Fruit constructor​
​var aBanana = new Fruit ("Banana", "Yellow");
​
​// Here, aBanana uses the name property from the aBanana object prototype
// which is Fruit.prototype:​
console.log(aBanana.name); // Banana​
​
​// Uses the showNameAndColor method from the Fruit object prototype,
// which is Plant.prototype.
// The aBanana object inherits all the properties
// and methods from both the Plant and Fruit functions.​
console.log(aBanana.showNameAndColor()); 
// I am a Banana and my color is yellow.
Note that the showNameAndColor method was inherited by the aBanana object even though it was defined all the way up the prototype chain on the Plant.prototype object.

Indeed, any object that uses the Fruit () constructor will inherit all the Fruit.prototype properties and methods and all the properties and methods from the Fruit’s prototype, which is Plant.prototype. This is the principal manner in which inheritance is implemented in JavaScript and the integral role the prototype chain has in the process.

Prototype Attribute: Accessing Properties on Objects

Prototype is also important for accessing properties and methods of objects.
The prototype attribute (or prototype object) of any object is the “parent” object where the inherited properties were originally defined.
This is loosely analogous to the way you might inherit your surname from your father—he is your “prototype parent.”

If we wanted to find out where your surname came from, we would first check to see if you created it yourself;
If not, the search will move to your prototype parent to see if you inherited it from him.
If it was not created by him, the search continues to his father (your father’s prototype parent).
Similarly, if you want to access a property of an object, the search for the property begins directly on the object.

If the JS runtime can’t find the property there,
it then looks for the property on the object’s prototype—the object it inherited its properties from.

If the property is not found on the object’s prototype, the search for the property then moves to prototype of the object’s prototype
(the father of the object’s father—the grandfather).

And this continues until there is no more prototype (no more great-grand father; no more lineage to follow).

This in essence is the prototype chain: the chain from an object’s prototype to its prototype’s prototype and onwards.
And JavaScript uses this prototype chain to look for properties and methods of an object.

If the property does not exist on any of the object’s prototype in its prototype chain, then the property does not exist and undefined is returned.

This prototype chain mechanism is essentially the same concept we have discussed above with the prototype-based inheritance, except we are now focusing specifically on how JavaScript accesses object properties and methods via the prototype object.

This example demonstrates the prototype chain of an object’s prototype object:

var myFriends = {name: "Pete"};
​
​// To find the name property below,
// the search will begin directly on the myFriends object 
// and will immediately find the name property because
// we defined the property name on the myFriend object.
// This could be thought of as a prototype chain with one link.​
console.log(myFriends.name);
​
​// In this example, the search for the toString () method
// will also begin on the myFriends’ object
// but because we never created a toString method on the myFriends object
// the compiler will then search for it on the myFriends prototype 
// (the object which it inherited its properties from).​
​
​// And since all objects created with the object literal inherits
// from Object.prototype, the toString method
// will be found on Object.prototype—see important note below
// for all properties inherited from Object.prototype. ​
​
myFriends.toString ();

Object.prototype Properties Inherited by all Objects
All objects in JavaScript inherit properties and methods from Object.prototype. These inherited properties and methods are constructor, hasOwnProperty (), isPrototypeOf (), propertyIsEnumerable (), toLocaleString (), toString (), and valueOf (). ECMAScript 5 also adds 4 accessor methods to Object.prototype.

Here is another example of the prototype chain:

function People () {
​this.superstar = "Michael Jackson";
}
​// Define "athlete" property on the People prototype so that
// "athlete" is accessible by all objects 
// that use the People () constructor.​

People.prototype.athlete = "Tiger Woods";
​
​var famousPerson = new People ();
famousPerson.superstar = "Steve Jobs";
​
​// The search for superstar will first look for
// the superstar property on the famousPerson object
// and since we defined it there, that is the property that will be used.
// Because we have overwritten the famousPerson’s superstar property
// with one directly on the famousPerson object
// the search will NOT proceed up the prototype chain. ​

console.log (famousPerson.superstar); // Steve Jobs​
​
​// Note that in ECMAScript 5 you can set a property to read only
// and in that case you cannot overwrite it as we just did.​
​
​// This will show the property from the famousPerson prototype
// (People.prototype), since the athlete property 
// was not defined on the famousPerson object itself.​
console.log (famousPerson.athlete); // Tiger Woods​
​
​// In this example, the search proceeds up the prototype chain
// and find the toString method on Object.prototype
// from which the Fruit object inherited—all objects ultimately 
// inherits from Object.prototype as we have noted before.​
console.log (famousPerson.toString()); // [object Object]

All built-in constructors (Array (), Number (), String (), etc.) were created from the Object constructor, and as such their prototype is Object.prototype.

__proto vs prototype

1-nDBFaMpflmSsIKfMLxWIvQ.jpeg

The prototype is a property on a constructor function that sets what will become the __proto__ property on the constructed object.

Every object can have another object as its prototype. Then the former object inherits all of its prototype’s properties. An object specifies its prototype via the internal property [[Prototype]]. The chain of objects connected by the [[Prototype]] property is called the prototype chain:

0-JoyuFSITeSY9iiqa.png

To see how prototype-based (or prototypal) inheritance works, let’s look at an example (with invented syntax for specifying the [[Prototype]] property):

var proto = {
 describe: function () {
 return 'name: '+this.name;
 }
};
var obj = {
 [[Prototype]]: proto,
 name: 'obj'
};
> obj.describe
[Function]
> obj.describe()
'name: obj'

another example

let cat = {breed: 'munchkin'};
let myCat = {name: 'Fluffykins'};
Object.setPrototypeOf(myCat, cat);
console.log(myCat.name); // Fluffykins
console.log(myCat.breed); // munchkin
console.log(myCat.__proto__); // { breed: 'munchkin' }
cat.tailLength = 15;
console.log(myCat.__proto__); // { breed: 'munchkin', tailLength: 15 }

For more information about Objects, This and Prototype, Please read their chapter from “You don’t know Js” Book.

Useful videos

Article about OOP in JS

Advertisements