function assert(value, desc) { var res = $("#results"); var li = document.createElement("li"); li.className = value ? "pass" : "fail"; li.appendChild(document.createTextNode(desc)); res.append(li); } // functions have prototype property which initially is set to an empty object // it doesnt serve much purpose until the function is used as a constructor function Person() {}; Person.prototype.goToWork = function () { return true; }; var person1 = Person(); assert(person1 === undefined, "person1 is undefined"); var person2 = new Person(); assert(person2 && person2.goToWork && person2.goToWork(), "person2 is a object with goToWork"); // each object in javascript has a implicit property named constructor that references the constructor that was used to create the object. prototype then is the property of constructor therefore each object has a way to find its prototype assert(true, person2.constructor); assert(true, person2.constructor.prototype.goToWork); assert(person2.constructor.prototype.goToWork(), "accessing prototype from instance"); assert(person2.constructor === Person, "constructor can be accessed via the constructor property"); assert(person2.constructor.prototype.goToWork === person2.goToWork, "both references are the same"); // constructor property can be used same as constructor var person3 = new person2.constructor(); assert(person3 instanceof Person, "person3 is instance of Person"); // property attached to prototype after obj instantiation is still available Person.prototype.goToPlay = function () { return true; }; assert(person2.goToPlay(), "property attached to prototype after object instantiation is still available "); // property references are resolved in the object first // prototype is consulted only if its not able to find it in property function Actor() { this.hasActed = false; this.act = function () { return !this.hasActed; }; }; var actor1 = new Actor(); Actor.prototype.act = function () { return this.hasActed; }; assert(actor1.act(), "if same method names exist on prototype and in instance, instance method has precedence"); // Inheritance using prototype chain can be achieved via doing something like Subclass.prototype = new Superclass() function Vehicle() { this.canDrive = true; }; function Car() {}; Car.prototype = new Vehicle(); var x5 = new Car(); assert(x5.canDrive, "Car is inheriting from Vehicle"); assert(x5 instanceof Car, "x5 is instance of Car"); assert(x5 instanceof Vehicle, "x5 is instance of Vehicle"); assert(x5 instanceof Object, "x5 is instance of Object"); // its advicable to avoid extending native types because they can cause undesirable results. Especially, extending object and number should be avoided // hasOwnProperty can be used to figure out whether properties are actually defined on an object instance versus imported from a prototype assert(!x5.hasOwnProperty('canDrive'), "canDrive is a property of prototype and not instance"); // Not calling constructors as constructors can give undesirable results function SomeConstructor(a, b) { this.c = a + b; }; // a private variable inside the function which is inside document.ready function var c = 6; // new is not used so this will get called as a function and not as a constructor var notUsedAsConstructor = SomeConstructor(1, 2); // hence this == window so window.c is 3 assert(window.c === 3, "window.c is 3"); // just c is the local c inside this anonymous function assert(c === 6, "c is 6 though"); assert(notUsedAsConstructor === undefined, "Didnt even get initialized");
<div id="results" />
body { margin:10px; } .pass { color:green; } .fail { color:red; text-decoration:line-through; }