Object Oriented JavaScript JavaScript • Really only 4 types in JavaScript – number, string, boolean – Object (includes arrays) • Remember that an object is really just a bunch of key-value pairs • Ways to create an object – Object literal: var obj = {}; – Create a new blank object: var obj = new Object(); – Write a constructor function: var pt = new Point(3,4); Constructor functions • Normal JavaScript function • Called with new like Java: var pt = new Point(3, 4); • Generally sets some properties and methods using “this” // Constructs and returns a new Point object. function Point(xValue, yValue) { this.x = xValue; this.y = yValue; this.distanceFromOrigin = function() { return Math.sqrt(this.x * this.x + this.y * this.y); }; } • By convention, constructors start with uppercase letters • Called with new Prototypes • every object contains a reference to a prototype object • a prototype can have a prototype, and so on – an object "inherits" all methods/data from its prototype(s) – doesn't have to make a copy of them; saves memory – prototypes allow JavaScript to mimic classes, inheritance Prototypes • Every function stores a “prototype” object property in it – When we define the Point function (constructor) a Point.prototype is created, which is an empty object {} – Every object created with the constructor will use the constructor’s prototype object as its prototype • When new is called – – – – A new object is created The constructor’s prototype is attached to the object Constructor is run on the new object this The new object is returned The Prototype Chain Constructors Point() Prototypes constructor prototype distanceToOrigin scale Instances prototype x y prototype x y Point Point The Prototype Chain Constructors Point() Prototypes constructor prototype distanceToOrigin scale prototype Object() Instances prototype x y prototype x y Point Point constructor prototype toString prototype (null) prototype Object The Prototype Chain Point.prototype x: 3 y: -4 __proto__ distanceToOrigin scale __proto__ Object.prototype toString __proto__ • When you ask for a property or method, JavaScript – sees if the object itself contains the property – recursively checks the object’s prototype – continues up the prototype chain until the end and returns undefined if it cannot find it. Using the Prototype for Methods // adding a method to the prototype function.prototype.name = function(params) { statements; }; Point.prototype.distanceFromOrigin = function() { return Math.sqrt(this.x * this.x + this.y * this.y); }; • Adding a property/method to a prototype will make it available to all objects that use that prototype • Any prototype can be modified – Including built-in types Inheritance using the Prototype function SuperClassName(parameters) { ... } function SubClassName(parameters) { ... } //Connect the prototype chain SubClassName.prototype = new SuperClassName(parameters); // Reset the constructor SubClassName.prototype.constructor = SubClassName • To make a subclass, set its prototype to an object of the superclass • Question: Why not this way? – SubClassName.prototype = SuperClassName.prototype; Inheritance // Constructor for Point3D "subclass" function Point3D(x, y, z) { this.x = x; this.y = y; this.z = z; } // set it to be a "subclass" of Point Point3D.prototype = new Point(0, 0); // override distanceFromOrigin method to be 3D Point3D.prototype.distanceFromOrigin = function() { return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z); }; Inheritance • There is no equivalent of the super keyword – no easy way to call the superclass's constructor • no built-in way to call an overridden superclass method – have to write it manually, e.g. var d = Point.prototype. distanceFromOrigin.apply(this); Or var d = Point.prototype. distanceFromOrigin.call(this); • Apply requires an array for function args • Call requires that function args are explicitly named function A() { this.x = 1; } // Define super class A.prototype.DoIt = function() { this.x += 1; } // Define Method B.prototype = new A; // Define sub-class B.prototype.constructor = B; function B() { A.call(this); // Call super-class constructor (if desired) this.y = 2; } B.prototype.DoIt = function() // Define Method { A.prototype.DoIt.call(this); // Call super-class method (if desired) this.y += 1; } b = new B; document.write((b instanceof A) + ', ' + (b instanceof B) + '<BR/>'); b.DoIt(); document.write(b.x + ', ' + b.y); Private Members function A() { var x = 7; this.GetX = function() { return x;} this.SetX = function(xT) { x = xT; } } obj = new A; obj2 = new A; document.write(obj.GetX() + ' ' + obj2.GetX()); obj.SetX(14); document.write(' ' + obj.GetX() + ' ' + obj2.GetX()); • Create private members using local variables and methods • Closure allows access to the local variables Namespaces • In JavaScript, there are only two scopes – Local and global • Problem: – In a large program, the namespace gets full – Using libraries complicates this more • Solution – The JavaScript Module Pattern The JavaScript Module Pattern • Using global variables and self-executing functions, create the equivalent of a module • Note: self-executing functions – Typically a function is just declared until called – Javascript allows us to declare the function and have it called immediately (function() { alert(“Hello World”); })(); OR (function() { alert(“Hello World”); }()); The JavaScript Module Pattern var cs340.module = (function () { // private variables and functions var foo = 'bar'; // constructor var module = function () { }; // prototype module.prototype = { constructor: module, something: function () { } }; // return the module return module; })(); var my_module = new cs340.module(); • Global variable – cs340.module • Everything else is private inside the module • Protected namespace • Returned object will run the constructor JavaScript Module Namespace catan.models.ClientModel = (function clientModelNameSpace(){ var ClientModel = (function ClientModelClass(){ var fullmodel = {}; function ClientModel(localConfig){ $("#debug").append("<br>In ClientModel Constructor"); } ClientModel.prototype.initFromServer = function(success){ … } ClientModel.prototype.getClientPlayerName = function(){ // TODO: Return the local player's correct name return "Sam"; } ClientModel.prototype.getClientPlayerColor = function(){ // TODO: Return the local player's correct color return "orange"; } return ClientModel; }()); return ClientModel; }()); var clientModel = new catan.models.ClientModel();