Skip to content

Instantly share code, notes, and snippets.

@abhi9bakshi
Last active September 18, 2020 23:09
Show Gist options
  • Save abhi9bakshi/1ddc344eec41e9bc8a0713ded1004df5 to your computer and use it in GitHub Desktop.
Save abhi9bakshi/1ddc344eec41e9bc8a0713ded1004df5 to your computer and use it in GitHub Desktop.
Pluralsight: JavaScript Objects and Prototypes

#Javascript Objects and Prototypes

##Chapter 1: Creating Javascript Objects

There are 4 ways of creating Javascript objects:

  1. Using Object Literals
var cat = {
  name: 'Fluffy',
  color: 'White'
}

display(cat.name);
  1. Using Constructor Functions
function Cat(name, color){
  this.name = name;
  this.color = color;
}

var cat = new Cat('Fluffy', 'White');
display(cat.name);
  1. Using Object.create
var cat = Object.create(Object.prototype,
{
  name: {
      value: 'Fluffy',
      enumerable: true,
      writable: true, 
      configurable: true
      },
    color: {
      value: 'White',
      enumerable: true,
      writable: true,
      configurable: true
      }
})

display(cat.name);
  1. Using ES6 classes
class Cat{
  constructor(name, color){
    this.name = name;
    this.color = color;
  }
}

var cat = new Cat('Fluffy', 'White');

display(cat.name);

##Chapter 2: Javascript Object Properties

###Using bracket notation

var cat = {
  name: 'Fluffy',
  color: 'White'
}

display(cat.color);
//Bracket notation
display(cat['color']);

###Using Javascript Object Properties

Displaying properties of an object

var cat = {
  name: 'Fluffy',
  color: 'White'
}

display(Object.getOwnPropertyDescriptor(cat, 'name'));

>>Object{
  value: Fluffy
  writable: true
  enumerable: true
  configurable: true
}
  1. Writable Attribute

Defines whether property's value can be changed from initial value

Object.defineProperty(cat, 'name', {writable: false});
  1. Enumerable Attribute

By default, properties of an object are enumerable, i.e. We can loop over them. We can change that by setting enumerable to false.

Object.defineProperty(cat, 'name', {writable: false});

Setting enumerable attribute to false affects looping through the object and JSON serialization.

  1. Configurable Attribute

Configurable attribute locks down a property to prevent certain attributes from being changed.

Object.defineProperty(cat, 'name', {configurable: false});

You can change the writeble attribute even when the configurable attribute is set to false.

###Using Getters and Setters

'use strict'

var cat = {
  name: 'Fluffy',
  color: 'White'
}

Object.defineProperty(cat, 'fullName',
{
  get: function(){
    return this.name.first + ' ' + this.name.last;
  },
  set: function(value){
    var nameParts = value.split(' ');
    this.name.first = nameParts[0];
    this.name.last = nameParts[1];
  }
})

cat.fullName = 'Muffin Top';
display(cat.fullName);
display(cat.name.first);
display(cat.name.last);

##Chapter 3: Javascript Prototypes and Inheritance

###Using DefineProperty to define properties of a javascript object in runtime

'use strict'

Object.defineProperty(Array.prototype, 'last', (get: function(){
  return this[this.length-1]
}});

var arr = ['red', 'blue', 'green']
var arr2 = ['one', 'two', 'three'];
display(arr.last);
display(arr2.last);

Output:

green
three

###What is prototype?

Definition: A function's prototype: A function's prototype is the object instance that will become the prototype for all objects created using this function as a constructor. An object's prototype: An object's prototype is the object instance from which the object is inherited.

A prototype is an object that exists on every function in javascript. It is just an empty object. Objects don't have a prototype property. They have a _proto_ property which points to the exact same object of it's parent function.

'use strict'

function Cat(name, color){
  this.name = name;
  this.color = color;
}
var fluffy = new Cat('Fluffy', 'White');

display(Cat.prototype);
display(fluffy.__proto__);
display(Cat.prototype === fluffy.__proto__);

Output:

Cat{
}

Cat{
}

true

###Instance vs Prototype

Let's say you have a function called Cat

function Cat(name, color){
  this.name = name;
  this.color = color;
}
Cat.prototype.age = 3;

You can check it's prototype age by typing

console.log(Cat.prototype.age);

which will return

3

Now, if you create an instances of that function

var fluffy = new Cat('Fluffy', 'White');
var muffin = new Cat('Muffin', 'Brown');

you can check age of each instance's prototype by typing

console.log(fluffy.__proto__.age);
console.log(muffin.__proto__.age);

which will return

3
3

This means that both prototype and __proto__ point to the same object.

However, the value in prototype object is not accessible if we loop through the object. You can verify this by typing

console.log(Object.keys(fluffy));

which will return

Array{
  0: name
  1: color
}

One interesting thing to note here is that, if you type console.log(fluffy.age), it also returns 3. What happens here is that, when javascript doesn't find age as a property of fluffy object, it checks it's prototype for the same, and upon finding, displays the value.

You can override this by creating a property of that object, e.g.

fluffy.age = 4;
console.log(fluffy.age);

which will return the output as

4

###Changing a function's prototype

Let's say we have the following code

'use strict'

function Cat(name, color){
  this.name = name;
  this.color = color;
}
Cat.prototype.age = 4;

var fluffy = new Cat('Fluffy', 'White');

If we type console.log(fluffy.age); we get the result as 4. Now, we can change the prototype of Cat function by adding the following code

Cat.prototype = { age: 5 }

You can see that adding this doesn't change the value of console.log(fluffy.age). This is because fluffy object was created before Cat function started pointing to another prototype.

If we create a new object now, we will see that it's prototype points to the new Cat prototype.

var muffin = new Cat('Muffin','Brown');
console.log(muffin.age);

which will give the result as 5.

###Object Oriented structure using prototypal inheritance

'use strict'

function Animal(voice) {
  this.voice = voice || 'grunt'
}
Animal.prototype.speak = function(){
  display(this.voice)
}

function Cat(name, color){
  Animal.call(this, 'Meow')
  this.name = name;
  this.color = color;
}
Cat.prototype = Object.create(Animal.-prptotype);
Cat.prototype.constructor = Cat;

var fluffy = new Cat('Fluffy', 'White');

display(fluffy.__prpto__.__proto__);

###Object Oriented structure using ES6 Classes

'use strict'

class Animal{
	constructor(voice){
	this.voice = voice || 'grunt';
	}
	speak(){
		console.log(this.voice);
	}
}

class Cat extends Animal{
	constructor(name, color){
		super('Meow');
		this.name = name;
		this.color = color;
	}
}

var fluffy = new Cat('Fluffy', 'White');
console.log(fluffy.speak());

##Display Source Code

//Display.js Source Code

function display() {
  for (var i = 0; i < arguments.length; i++) {
    if (typeof arguments[i] === 'object') 
      displayObject(arguments[i])
    else
      displayValue(arguments[i], true)
  }
}

function displayObject(object) {
  if (object == null)
    displayValue('null')
  displayValue(getTypeName(object) + ' {')
  for(var propertyName in object) {
    if (propertyName != 'constructor') {
      displayValue(propertyName + ': ' + object[propertyName], false, true);
    }
  }
  displayValue('}', true)
}

function displayValue(value, addMargin, addPadding) {
  var div = document.createElement('div');
  div.style.fontSize='32px'
  if (addMargin)
    div.style.marginBottom='30px'
  if (addPadding)
    div.style.paddingLeft='30px'
  div.textContent = value;
  document.body.appendChild(div)
}

function getTypeName(object) {
   var funcNameRegex = /function (.{1,})\(/;
   var results = (funcNameRegex).exec(object.constructor.toString());
   return (results && results.length > 1) ? results[1] : "";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment