oop beginner javascript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE HTML> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>Object Oriented JavaScript</title> | |
</head> | |
<body> | |
<script type="text/javascript"> | |
// A basic JavaScript object with properties and a method | |
var customer = { | |
name: 'Tom Smith', | |
speak: function(){ | |
// this allows you to reference a specific objects value | |
// without knowing the objects name | |
return "My name is " + this.name; | |
}, | |
// Objects can contain other objects | |
address: { | |
street: '123 Main St', | |
city: 'Pittsburgh', | |
state: 'PA' | |
} | |
}; | |
document.write(customer.speak()+ "<br />"); | |
// You access properties and object properties like this | |
document.write(customer.name + " lives at " + customer.address.street + "<br />"); | |
// You can add properties | |
customer.address.country = "US"; | |
document.write(customer.address.country + "<br />"); | |
// Creating multiple objects of the same type with Constructor | |
// Functions. Constructors provide the functions that classes | |
// provide in other languages | |
function Person(name, street) { | |
// this allows us to refer to an object even though we | |
// don't know its name before it is created | |
this.name = name; | |
this.street = street; | |
this.info = function(){ | |
return "My name is " + this.name + " and I live on " + this.street; | |
} | |
} | |
// You call constructor functions with new | |
var bobSmith = new Person("Bob Smith", "234 Main St"); | |
document.write(bobSmith.info() + "<br />"); | |
// instanceof tells you if an object is of a certain type | |
document.write("Bob is a person : " + (bobSmith instanceof Person) + "<br />"); | |
// You can pass an object to a function and change values | |
function changeName(person){ | |
person.name = "Sue Smith"; | |
} | |
changeName(bobSmith); | |
document.write("Bob became " + bobSmith.name + "<br />"); | |
// Objects are only equal if they reference the same object | |
var person1 = new Person("Paul", "123 Main"); | |
var person2 = new Person("Paul", "123 Main"); | |
document.write("Are they equal " + (person1 == person2) + "<br />"); | |
// ---------- PROTOTYPE ---------- | |
// Every function has a prototype property that contains an object | |
// You can add properties and methods to the prototype object | |
// and then when you call for them to execute they are used | |
// just as if they belonged to the object | |
function getSum(num1, num2){ | |
return num1 + num2; | |
} | |
// Get the number of function arguments | |
document.write("Num of arguments : " + getSum.length + "<br />"); | |
// You can add properties and methods to this object | |
function Mammal(name){ | |
this.name = name; | |
this.getInfo = function(){ | |
return "The mammals name is " + this.name; | |
} | |
} | |
// Use prototype to add a property | |
Mammal.prototype.sound = "Grrrrr"; | |
// Use it to add a method | |
Mammal.prototype.makeSound = function() { | |
return this.name + " says " + this.sound; | |
}; | |
var grover = new Mammal("Grover"); | |
document.write(grover.makeSound() + "<br />"); | |
// List all properties of an object | |
for( var prop in grover){ | |
document.write(prop + " : " + grover[prop] + "<br />"); | |
} | |
// Check which property belongs to prototype vs. the object grover | |
document.write("name Property of Grover : " + grover.hasOwnProperty("name") + "<br />"); | |
document.write("sound Property of Grover : " + grover.hasOwnProperty("sound") + "<br />"); | |
// You can add methods to built in JS objects | |
Array.prototype.inArray = function inArray(value){ | |
for(i = 0; i < this.length; i++){ | |
if(this[i] === value){ | |
return true; | |
} | |
} | |
return false; | |
} | |
var sampArray = [1,2,3,4,5]; | |
document.write("3 in array : " + sampArray.inArray(3) + "<br />"); | |
// ---------- PRIVATE PROPERTIES ---------- | |
// All properties in an object are public in that any function | |
// can modify or delete these properties. | |
// You can make properties private by declaring them as | |
// variables in a constructor | |
function SecretCode(){ | |
// This value can't be accessed directly | |
var secretNum = 78; | |
// This function can access secretNum | |
this.guessNum = function(num){ | |
if(num > 78){ | |
return "Lower"; | |
} else if(num < 78){ | |
return "Higher"; | |
} else { | |
return "You Guessed It"; | |
} | |
} | |
} | |
var secret = new SecretCode(); | |
// Returns undefined | |
document.write("Value of secretNum : " + secret.secretNum + "<br />"); | |
document.write("Is 70 the number : " + secret.guessNum(70) + "<br />"); | |
// Even if we add another function it can't access the secretNum | |
SecretCode.prototype.getSecret = function(){ | |
return this.secretNum; | |
} | |
document.write("The secret number is " + secret.getSecret() + "<br />"); | |
// ---------- GETTERS AND SETTERS ---------- | |
// Getters and Setters can protect data, or provide useful | |
// ways to set its value | |
// I'll show you a bunch of getters and setters you may come | |
// in contact with | |
var address = { | |
street: "No Street", | |
city: "No City", | |
state: "No State", | |
// Provides styled data all at once | |
get getAddress() { | |
return this.street + ", " + this.city + ", " + this.state; | |
}, | |
// Allows the user to set 3 values with 1 | |
set setAddress (theAddress) { | |
var parts = theAddress.toString().split(", "); | |
this.street = parts[0] || ''; | |
this.city = parts[1] || ''; | |
this.state = parts[2] || ''; | |
} | |
} | |
address.setAddress = "123 Main St, Pittsburgh, PA"; | |
document.write("Address : " + address.getAddress + "<br />"); | |
document.write("City : " + address.city + "<br />"); | |
// ---------- CONSTRUCTOR GETTERS AND SETTERS ---------- | |
// Still used even though it is (Deprecated) | |
function Coordinates(){ | |
this.latitude = 0.0; | |
this.longitude = 0.0; | |
} | |
// Define the getter with the prototype to assign it to with | |
// the property name and the getter function | |
Object.__defineGetter__.call(Coordinates.prototype, "getCoords", function(){ | |
return "Lat : " + this.latitude + " Long: " + this.longitude; | |
}); | |
// Define the setter with the prototype to assign it to with | |
// the property name and the setter function | |
Object.__defineSetter__.call(Coordinates.prototype, "setCoords", function(coords){ | |
var parts = coords.toString().split(", "); | |
this.latitude = parts[0] || ''; | |
this.longitude = parts[1] || ''; | |
}); | |
var testCoords = new Coordinates(); | |
testCoords.setCoords = "40.71, 74.00"; | |
document.write("Coordinates : " + testCoords.getCoords + "<br />"); | |
// ---------- GETTERS AND SETTERS WITH DEFINEPROPERTY ---------- | |
function Point(){ | |
this.xPos = 0; | |
this.yPos = 0; | |
} | |
// Use defineProperty to set getters and setters | |
// Pass the prototype to attach to along with the property name | |
// and define the functions to associate with get and set | |
Object.defineProperty(Point.prototype, "pointPos", { | |
get: function(){ | |
return "X: " + this.xPos + " Y: " + this.yPos; | |
}, | |
set: function(thePoint){ | |
var parts = thePoint.toString().split(", "); | |
this.xPos = parts[0] || ''; | |
this.yPos = parts[1] || ''; | |
} | |
}); | |
var aPoint = new Point(); | |
aPoint.pointPos = "100, 200"; | |
document.write("Point Position : " + aPoint.pointPos + "<br />"); | |
// ---------- ECMASCRIPT 5.1 GETTERS AND SETTERS ---------- | |
var Circle = function (radius) { | |
this._radius = radius; | |
}; | |
Circle.prototype = { | |
set radius(radius) { this._radius = radius; }, | |
get radius() { return this._radius; }, | |
get area() { return Math.PI * (this._radius * this._radius); } | |
}; | |
var circ = new Circle(10); | |
circ.radius = 15; | |
document.write("A circle with radius " + circ.radius + " has an area of " + circ.area.toFixed(2) + "<br />"); | |
// ---------- INHERITANCE ---------- | |
// When we ask for a property if it isn't found in the main object | |
// then it is searched for in the prototype object. We are able | |
// to inherit methods and variables from any object in a | |
// chain of objects. | |
function Animal(){ | |
this.name = "Animal"; | |
// toString is a function in the main Object that every | |
// object inherits from | |
this.toString = function() { | |
return "My name is : " + this.name; | |
}; | |
} | |
function Canine(){ | |
this.name = "Canine"; | |
} | |
function Wolf(){ | |
this.name = "Wolf"; | |
} | |
// Overwrite the prototype for Canine and Wolf | |
Canine.prototype = new Animal(); | |
Wolf.prototype = new Canine(); | |
// After you overwrite prototype its constructor points to the | |
// main object object so you have to reset the constructor after | |
Canine.prototype.constructor = Canine; | |
Wolf.prototype.constructor = Wolf; | |
var arcticWolf = new Wolf(); | |
// Wolf inherits toString from Animal | |
document.write(arcticWolf.toString() + "<br />"); | |
document.write("Wolf instance of Animal : " + (arcticWolf instanceof Animal) + "<br />"); | |
// Properties added to any object in the chain is inherited | |
Animal.prototype.sound = "Grrrrr"; | |
Animal.prototype.getSound = function(){ | |
return this.name + " says " + this.sound; | |
} | |
Canine.prototype.sound = "Woof"; | |
Wolf.prototype.sound = "Grrrr Wooof"; | |
document.write(arcticWolf.getSound() + "<br />"); | |
// More often then not it makes more sense to just inherit the | |
// prototype to speed up the lookup process | |
function Rodent(){ | |
this.name = "Rodent"; | |
} | |
function Rat(){ | |
this.name = "Rat"; | |
} | |
Rodent.prototype = new Animal(); | |
Rat.prototype = Rodent.prototype; | |
Rodent.prototype.constructor = Rodent; | |
Rat.prototype.constructor = Rat; | |
var caneRat = new Rat(); | |
// Wolf inherits toString from Animal | |
document.write(caneRat.toString() + "<br />"); | |
// ---------- INTERMEDIATE FUNCTION INHERITANCE ---------- | |
function extend(Child, Parent){ | |
var Temp = function(){}; | |
Temp.prototype = Parent.prototype; | |
Child.prototype = new Temp(); | |
Child.prototype.constructor = Child; | |
} | |
function Deer(){ | |
this.name = "Deer"; | |
this.sound = "Snort"; | |
} | |
extend(Deer, Animal); | |
var elk = new Deer(); | |
document.write(elk.getSound() + "<br />"); | |
// ---------- CALL PARENT METHODS ---------- | |
function Vehicle(name) { | |
this.name = "Vehicle" | |
} | |
// Functions for the parent object | |
Vehicle.prototype = { | |
drive: function(){ | |
return this.name + " drives forward"; | |
}, | |
stop: function(){ | |
return this.name + " stops"; | |
} | |
} | |
function Truck(name) { | |
this.name = name | |
} | |
// Inherit from Vehicle | |
Truck.prototype = new Vehicle(); | |
Truck.prototype.constructor = Truck; | |
// Overwrite drive parent method | |
Truck.prototype.drive = function(){ | |
// Call the parent method with apply so that the parent | |
// method can access the Trucks name value | |
var driveMsg = Vehicle.prototype.drive.apply(this); | |
return driveMsg += " through a field"; | |
} | |
var jeep = new Truck("Jeep"); | |
document.write(jeep.drive() + "<br />"); | |
document.write(jeep.stop() + "<br />"); | |
// ---------- SINGLETON PATTERN ---------- | |
// Singletons are used when you only ever want 1 object to | |
// be created | |
// Let's say you want to create a game character with fixed | |
// stats | |
function Hero(name){ | |
// Check if the object exists | |
if(typeof Hero.instance === 'object'){ | |
// If it does return it | |
return Hero.instance; | |
} | |
// if it doesn't then create the hero | |
this.name = name; | |
Hero.instance = this; | |
return this; | |
} | |
var derekHero = new Hero("Derek"); | |
document.write("Are hero is " + derekHero.name + "<br />"); | |
// This won't change the name to Paul | |
var paulHero = new Hero("Paul"); | |
document.write("Are hero is " + paulHero.name + "<br />"); | |
// ---------- FACTORY PATTERN ---------- | |
// The factory pattern can be used to generate different | |
// objects on request | |
function Sword(desc){ | |
this.weaponType = "Sword"; | |
this.metal = desc.metal || "Steel"; | |
this.style = desc.style || "Longsword"; | |
this.hasMagic = desc.hasMagic || false; | |
} | |
function Bow(desc){ | |
this.weaponType = "Bow"; | |
this.material = desc.material || "Wood"; | |
this.style = desc.style || "Longbow"; | |
this.hasMagic = desc.hasMagic || false; | |
} | |
function WeaponFactory(){}; | |
WeaponFactory.prototype.makeWeapon = function(desc){ | |
var weaponClass = null; | |
if(desc.weaponType === "Sword"){ | |
weaponClass = Sword; | |
} else if (desc.weaponType === "Bow"){ | |
weaponClass = Bow; | |
} else { | |
return false; | |
} | |
return new weaponClass(desc); | |
} | |
var myWeaponFact = new WeaponFactory(); | |
var bladeFist = myWeaponFact.makeWeapon({ | |
weaponType: "Sword", | |
metal: "Dark Iron", | |
style: "Scythe", | |
hasMagic: true | |
}); | |
document.write(bladeFist.weaponType + " of type " + bladeFist.style + " crafted from " + bladeFist.metal + "<br />"); | |
// ---------- DECORATOR PATTERN ---------- | |
// The decorator pattern allows you alter an object at run time | |
function Pizza(price){ | |
this.price = price || 10; | |
} | |
Pizza.prototype.getPrice = function(){ | |
return this.price; | |
} | |
function ExtraCheese(pizza){ | |
var prevPrice = pizza.price; | |
pizza.price = prevPrice + 1; | |
} | |
var myPizza = new Pizza(10); | |
ExtraCheese(myPizza); | |
document.write("Cost of Pizza : $" + myPizza.price + "<br />"); | |
// ---------- OBSERVER PATTERN ---------- | |
// A single object notifies many objects (observers) when a | |
// state change occurs | |
var Observable = function() { | |
this.subscribers = []; | |
} | |
Observable.prototype = { | |
subscribe: function(subscriber) { | |
// Add the subscriber object to the list | |
this.subscribers.push(subscriber); | |
}, | |
unsubscribe: function(unsubscriber) { | |
// Cycle through the subscriber array and delete | |
// the unsubscriber | |
for (i = 0; i < this.subscribers.length; i++) { | |
if (this.subscribers[i] === unsubscriber) { | |
this.subscribers.splice(i, 1); | |
// We assume it only subscribed once so we | |
// leave after it is found | |
return unsubscriber.name; | |
} | |
} | |
}, | |
publish: function(data) { | |
// Cycle through all subscribers and send them the update | |
for (i = 0; i < this.subscribers.length; i++) { | |
this.subscribers[i].receiveData(data); | |
} | |
} | |
}; | |
var OrganFanny = { | |
name: "Organ Fanny", | |
receiveData: function(data){ | |
document.write(this.name + " received your info : " + data + "<br />"); | |
} | |
} | |
var BoldmanYaks = { | |
name: "Boldman Yaks", | |
receiveData: function(data){ | |
document.write(this.name + " received your info : " + data + "<br />"); | |
} | |
} | |
// Add subscribers and alert them | |
observable = new Observable(); | |
observable.subscribe(OrganFanny); | |
observable.subscribe(BoldmanYaks); | |
observable.publish('IBM at $145.30'); | |
document.write(observable.unsubscribe(OrganFanny) + " Unsubscribed<br />"); | |
observable.publish('IBM at $145.33'); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment