Quantcast
Channel: CleanCode NZ
Viewing all articles
Browse latest Browse all 28

javascript in Depth

$
0
0

In javascript, have you ever been confused by prototype and __proto__, what is best way to do inheritance? what the type of object it actually is? where are those apply or call methods from? and what differences they have when functions are declared in different ways. There has been an urge to dive down to have a look of what those foundational concepts are.

This article even though touches some of those foundational elements of javascript programming, it still is written from higher level view with the use of language as main purpose. The tests are done in chrome which is implementation of ECMA-262-5. They have not been tested in other browsers, but I believe they generally should be same, I have tried to avoid those tricky topics that do not seem to be very relevant to main stream daily javascript programming tasks.

Data types in javascript:

Primitive types

Undefined, Null, Boolean, String, Number.

They are not objects, they do not have neither prototypes, nor constructors.

Object type
Before going into details, there are two important built in objects we need to be familiar with

 Object and Function prototype

Object and Function prototype


They can be retrieved and inspected like this
  var o1 = Object.prototype;
  var o2= Function.prototype;

Here is the pseudo code when an object o created by calling new F().

Object creation

Object creation

What it does is to run the function itself to initialize the object, then set function.prototype to __proto__ of new object.

A copule of points to note:

1. The function’s prototype can be changed and its constructor can also be changed but the object shape fully depends on the function itself not its prototype and constructor of prototype.

2. Prototype chain is through __proto__ property of an object which is the prototype of the function F. Change of prototype of function F affects the prototype chain, not the object shape

3. An object does not have prototype property. It has __proto__

4. The inheritance of methods and properties comes from a) prototype chain which is from function.prototype and b) the function itself, all fields created in function will be inherited into new object, but fields belonging to prototype will remain in prototype

5. The type of objects is ‘Object’ rather than F as this can be proven from .toString()

6. When F.prototype is not an object(for example it is set to null), then __proto__ will be set Object.prototype, this ensures that the new object looks like an object which has implementations like toString() etc.

7. There are a few other static functions implemented by Object() but they are not part of prototype chain

Special cases:

var o1= {}

Literal object or objected created by object initializer is calling actually

var o1= new Object(),

So the constructor function is Object() function, and o1.__proto__ is Object.prototype.

o1.toString() is exactly a good example of prototype chain search, where toString() is implemented by Object.prototype(aka o1.__proto__) rather by o1

Another way of creating an empty project is

var o1= Object.create(Object.prorotype)

What this does is to pass the parameter to __proto__ property of new object, in this way you can create an object with no __proto__ by Object.create(null);

Function type

This is another important prototype in javascript Function.prototype which is inherited by every function object.

Following is pseudo code of a function declaration.

Function creation

Function creation

A couple of points

1. A function object has at least two properties, one is __proto__ just as an object does, the __proto__ of a function object is Function.prototype which has generic methods of functions like apply, call ect.

Another one is prototype, which has a constructor pointing it to the function itself, and __proto__ which is a generic Object.prototype. It is this prototype property that is used for object creation

2. When the function is used for object creation, it is prototype object is passed to __proto__ of new object

3. An object created by new or literal DOES not have prototype property, prototype only belongs to a function object. ‘prototype is undefined’ is likely a mistake of this.

4. When the function is used for just simple execution, the prototype is not used.

Function instanceof

In javascript, there is no exact type of an object, they are either Object or Function, but they do have inheritance, instanceof function can give you some clue what type the object is, and it is tricky.

alert(a instanceof B);

What function instanceof does is testing if B.prototype in the prototype chain(chain of __proto__) of a

A few special cases

   function Animal() {
            this.isAnimal = true;
  }
  function Dog() {
            this.isDog= true;
  }
  var a = new Animal();
//example 1
  Animal.prototype.constructor = Dog;

var isdog = a instanceof Dog; // false
var isanimal = a instanceof Animal; // true
// example 2
  Animal.prototype = {
                constructor: Dog
        };

  Var b = new Animal();

  isdog = b instanceof Dog; // false
  isanimal = b instanceof Animal; // true
// example 3
  var c = new Animal();
  Animal.prototype = {
                constructor: Dog
            };
  isdog = c instanceof Dog; // false
  isanimal = c instanceof Animal; // false

// example 4
  var d = new Animal();
  Animal.prototype =  Dog.prototype ;

  isdog = c instanceof Dog; // true
  isanimal = c instanceof Animal; // true

Example 1: tells us that instance has nothing to do with constructor,
Example 2: even you changed animal prototype to something looks like a dog, b.__proto__still is Animal.prototype so it is still animal

Example 3: as Animal.prototype reassigned after the object c creation, c.__proto__is pointing to previous Animal.prototype not the new one which is {constructor:Dog,}, this is to do with ‘copy object by sharing’, more on this later

Example 4: As Animal.prototype is the same as Dog.prototype , so they both return true

Constructor
Constructor is property of prototype object, I saw a lot of people playing with constructor, but I do not see any significance of constructor except that it gives a reference of function.

When object is created using new F(), the F function is used to initialize the object even you can replace F.prototype and F.prototype.constructor before the instantiation, the roles F.prototype played in object creation is known, but if you change constructor, what effect it has on object? I can not see any.

Evaluation strategy
It involves how object are passed into function as a parameter, it is neither by reference nor by value, javascript strategy is called by sharing

var foo = {x: 10, y: 20};
var bar = foo;
alert(bar === foo); // true
bar.x = 100;
bar.y = 200;

alert([foo.x, foo.y]); // [100, 200]

bar= {z:300};
alert([foo.x, foo.y]); // [100, 200]

The characters of call by sharing is that it is copy of address, any change made to bar object like adding a new property, changing property value will be done in foo as well, but when you assign bar to another object, foo will not follow, this dereferences bar from foo. While normal by reference referencing in other languages does not support dereferencing

This has some implications. Like an example as below

function B() { }
function A() { }
var a = new A();

A.prototype.x = 10;

alert(a.x); // 10

A.prototype = {
                constructor: B,
                y: 20
         }

alert(a.y); // undefined

var b = new A();

alert(b.y) //20

Normally you would think that a.y should be 20, but the fact is when you modify A.prototype, like adding x property to it, a.__proto__ still shares with A.prototype, but when you assign A.prototype to a new object, it creates a new reference for A.prototype, old ones do not follow.

Closure

var foo = {};

(function initialize() {

  var x = 10;

  foo.bar = function () {
    alert(x);
  };
  X =20;
})();

foo.bar(); // 20;

alert(x); // "x" is not defined

When foo.bar is created by initialize(), there is Closure scope that is added to the foo.bar function which includes local variable x of function initialize(), the tricky thing is x in the closure scope for function foo.bar is through reference, that is the change of x in the local scope after the function definition will be picked up.

The Closure makes perfect namespaces programming for javascript, while x is not visible outside initialize(), the functions defined inside initialize() can be put under a namespace, and accessible outside initialize()

More often people like to use anonymous function rather than a named function initialize() to define a namespace

var foo = {};

(function() {

var x =10

foo.bar = function () {
    this.y=x;
  };

foo.bar.prototype.z=20;
})();

var o= new foo.bar();

Do not forget to expose the namespace in the global context either as in the example var foo={} or within the self executing function by attaching the foo name space to global object windows

//var foo = {};

(function() {
var foo ={}

foo.bar = function () {
    this.y=x;
  };

// set it to global object
windows.foo=foo;
})();

var o =new foo.bar();

Function declaration and function expression
Function declaration examples

function F(){}
// or

Function G() {
   Function H(){};
}

Function declaration only happens when in main program level or within another function.

Function declaration is put in VO(Variable object) or AO(Activation Object), and has Closures if it is in AO and it is created in execution context entering phrase, so it is accessible anywhere in that execution context, even before its declaration.

Function expression examples

var foo = function () {
  ...
};
//or
var foo = function _foo() {
  ...
};

First example is function expression involving an anonymous function while the second is involving the a named function, interestingly enough, _foo is not accessible outside function, but accessible within the function.

While function expression is meant for in line execution, not created in execution context entering phrase, but in code execution, so the function call cannot be performed before the function expression.

This value
This value within a function is totally dependent on the context the execution, normally is the reference of the caller, at program level, the caller is global object.

function foo() {
  alert(this);
}

foo(); // global

alert(foo === foo.prototype.constructor); // true

// but with another form of the call expression
// of the same function, this value is different
 foo.prototype.constructor(); // foo.prototype

The ‘this’ value within a constructor function we all know is the new object, this also falls into the caller category, another important point is even the function is deep down in the prototype chain, this in those functions points to the root object, rather than that __proto__ object.

There are two situations where you can manually set ‘this’ value of a function, they two methods defined in Function.prototype, apply() and call(), the first parameter of these two function is ‘this’

Summary:

Here we looked at some foundation aspects of javascript programming, that javascript have primitive types, Object type and Function type, the constructor function’s prototype is passed to __proto__ of new object. Also we looked at a few confusing concepts like this value, function declaration and function expression. The javascript core helped me a lot to understand these concepts.


Viewing all articles
Browse latest Browse all 28

Trending Articles