Inside Javascript Objects

Outline

  1. Objects
  2. Functions
  3. Prototype
  4. The new operator
  5. The instanceof operator
  6. Implementing Classical Inheritance

Objects

A simple object.

p = {x: 1, y: 2};
a = p.x; // 1
b = p.y; // 2

New properties can be added at runtime.
p.z = p.x + p.y; // 3

Functions

Functions are special objects which are callable.
function square(x) { 
    return x*x; 
}
square(4); // returns 16

var sq = square;
sq(4); // returns 16
You can also add properties to it like other objects.
square.x = 1;

What is "this"?

The body of the function has access to two magic variables: this and arguments.

The value of this variable depends on how the function is called.

Javascript has a top-level object, that maintains the global variables. In the context of web browser, the top-level object is the window object.

What is "this"?

The function object has an apply method. Calling f(2) is equivalent to calling:

f.apply(null, [2]);

And calling a.f(2) is equivalent to calling:

f.apply(a, [2]);

What is "this"?

An example:
function square_me() {
    return this.value * this.value;
}

var n = {"value": 2};
n.square = square_me;

n.square(); // returns 4
square_me.apply(n, []); // returns 4

The arguments variable

The special variable arguments contains the list of arguments passed to the function.

A simple example to demonstrate use of arguments:
function count() {
    return arguments.length;
}

count();        // 0
count(1, 2, 3); // 3
count(4, 5);    // 2

The new operator

There is another way to create objects, using the new operator.
function Point(x, y) {
    this.x = x;
    this.y = y;
}
var p = new Point(3, 4);    

p.x; // 3
p.y; // 4
The new operator creates a new object and passes it as this object to the Point function.

The prototype object

Every function has a special property prototype and all the properties of the prototype object are accessible to the objects created using that function.
function Point(x, y) {
    this.x = x;
    this.y = y;
}
var p = new Point(3, 4);    
Point.prototype.name = "Point"; // Adding a name property to prototype
p.name; // returns "Point"
If we add a name property to p, it effects only that object and not the prototype.
p.name = "p";
Point.prototype.name; // will still be "Point"
It is typically used for adding methods.
Point.prototype.magnitude = function() {
    return Math.sqrt(this.x*this.x + this.y*this.y);
}
p.magnitude(); // returns 5

The prototype object

Function prototype can be changed too.
function F() {}
F.prototype.x = 1;

var f1 = new F();
f1.x; // 1

// Changing the function prototype here!
F.prototype = {"x": 2}; 
var f2 = new F();

f2.x; // 2

// What happen to previously created objects when prototype changes?
f1.x; // ??

__proto__

Some Javascript engines let you access the prototype of an object through a special property __proto__.
p.__proto__ == Point.prototype; // true
It is even possible to modify the __proto__ property.
p.__proto__ = {
    "name": "foo",
};

p.name; // "foo"

The prototype object

Here is a diagram showing 2 Point objects.
p1                          p2
+-----------+         +-----------+
| x         |-> 1     | x         |---> 5
+-----------+         +-----------+         
| y         |-> 2     | y         |---> 6   
+-----------+         +-----------+         
| __proto__ |----+  +-| __proto__ |
+-----------+    |  | +-----------+         
                 |  |                            
                 |  |
                 v  v 
             Point.prototype                      
             +--------------+                     
             | name         | --> "Point"         
             +--------------+
             | magnitude    | --> function() {...}
             +--------------+                     

How to implement the new operator?

function new_operator(func, args) {
    var obj = {};
    obj.__proto__ = func.prototype;
    func.apply(obj, args);
    return obj;
}

var p1 = new_operator(Point, [1, 2]);
p1 instanceof Point; // true
p1.x; // 1
p1.y; // 2
WARNING: Works only in the JS engines where __proto__ is supported.

How does it work?

function new_operator(func, args) {
    var obj = {};
    obj.__proto__ = func.prototype;
    func.apply(obj, args);
    return obj;
}

var p1 = new_operator(Point, [1, 2]);
1. Create an empty object
obj           
+-----------+ 
|           |
+-----------+ 
2. Link it with prototype
obj            +> Point.prototype
+-----------+  | +---------------+
| __proto__ |--+ |      ....     |
+-----------+    +---------------+
3. Call the constructor
obj              +> Point.prototype
+-----------+    |  +-------------+
| x         |->1 |  |      ....   |
+-----------+    |  +-------------+
| y         |->2 |
+-----------+    |
| __proto__ |----+
+-----------+     

The Prototype Chain

Lets try a tricky example now.
function F() {
    this.f = "F";
}
function G() {
    this.g = "G";
}
G.prototype.h = "H";

// Here is the magic. Prototype of F is an instance of G.
F.prototype = new G(); 

x = new F();
x.h; // ??
Yes, you guessed it right. It will be "H".

The Prototype Chain

But how does it work?
 x                 +> F.prototype       +> G.prototype
+-----------+      | +-----------+      | +-----------+        
| f         |->"F" | | g         |->"G" | | h         |-> "H" 
+-----------+      | +-----------+      | +-----------+        
| __proto__ |------+ | __proto__ |------+ | __proto__ |-> ...
+-----------+        +-----------+        +-----------+        
Prototypes can be chained like this! Looks like some kind of inheritance?

The instanceof operator

Quoting Mozilla docs:
The instanceof operator tests whether an object has in its prototype chain the prototype property of a constructor. Syntax: object instanceof constructor
In simple words, it lets you find if an object is instance of a function.
var p = new Point(3, 4);
p instanceof Point; // true
p instanceof Object; // true

The instanceof operator

One more example to understand this better.
function F() {}
function G() {}

f = new F();
f instanceof F; // true
f instanceof G; // false

G.prototype = F.prototype; 
f instanceof G; // true
f instanceof F; // true

Implementing the instanceof operator

It is not too hard to implement the instanceof operator as a function.
function  my_instanceof(object, constructor) {
    if (object === Object.prototype)
        return false;
    return (object.__proto__ === constructor.prototype 
        || my_instanceof(object.__proto__, constructor));
}    

Implementing the instanceof operator

There are slight deviations in the behavior of instanceof and my_instanceof for primitive objects like numbers.
my_instanceof(1, Number);   // true
my_instanceof(1, Object);   // true

1 instanceof Number;    // false
1 instanceof Object;    // false
Do you know why?

Implementing Classical Inheritance

Now lets try to create classes similar to the traditional programming languages like Java and Ruby. We should build the following:

Implementing Classical Inheritance

Classical Inheritance - First Attempt

No support for inheritance yet.
// Version 1 of Class implementation.
function Class(members) {
    var F = function() {
        if (members.init) {
            members.init.apply(this, arguments);
        }
    };
    F.prototype = members;
    return F;
}

How does it work?

var Animal = Class({
    init: function(name) {
        this.name = name;
    },
    eat: function() {
        return this.name + " is eating";
    }});
 F / Animal      +---> members
+-----------+    |    +-------+
| prototype |----+    | init  |
+-----------+         +-------+
                      | eat   |
                      +-------+

How does it work?

var a = new Animal("dog");
a.eat(); // "dog is eating"
 a                  +> members       
+-----------+       | +------+
| name      |->"dog"| | init | 
+-----------+       | +------+
| __proto__ |-------+ | eat  |
+-----------+         +------+

Classical Inheritance (Continued...)

OK. We've solved the first part. What about the inheritance?

Lets borrow some ideas from Douglas Crockford.

function object(o) {
    function F() {}
    F.prototype = o;
    return new F();
}
"The object function untangles JavaScript's constructor pattern, achieving true prototypal inheritance. It takes an old object as a parameter and returns an empty new object that inherits from the old one."

How does it work?

y = object(x);
    
 y                x
+-----------+    +-----+
| __proto__ |--->| ... |
+-----------+    +-----+
z = object(y);

 z                y                x
+-----------+    +-----------+    +-----+
| __proto__ |--->| __proto__ |--->| ... |
+-----------+    +-----------+    +-----+

Classical Inheritance - Second Attempt

// Version 2 of Class implementation
function Class(members) {
    var F = function() {
        if (members.init) {
            members.init.apply(this, arguments);
        }
    };
    F.prototype = members;

    F.extend = function(members) {
        // Creating new object using the prototype of F
        var new_members = object(F.prototype);

        // and adding members to it.
        for (var name in members) {
            new_members[name] = members[name];
        }
        return Class(new_members);
    };

    return F;
}    

Classical Inheritance - Second Attempt

var Bird = Animal.extend({
    fly: function() {
        return this.name + " is flying";
    }
});
 Bird.prototype  +--> Animal.prototype
+-----------+    |   +----------------+
| fly       |    |   |      ...       |
+-----------+    |   +----------------+
| __proto__ |----+   
+-----------+                             

Classical Inheritance - Second Attempt

And when you create an object:
var b = new Bird("sparrow");
    
b                +--> Bird.prototype  +--> Animal.prototype 
+-----------+    |   +-----------+    |   +---------------+
| name      |    |   | fly       |    |   |      ...      |
+-----------+    |   +-----------+    |   +---------------+
| __proto__ |----+   | __proto__ |----+   
+-----------+        +-----------+

Want to learn more?

Questions?

/

#