This repository was used to demonstrate simple Object Oriented Javascript.
Global Scope
function setGlobal(){
config = "my setting";
}
function getGlobal(){
console.log(config);
}
Function Scope
function setGlobal(){
var config = "my setting";
}
// This throw error "config is not defined"
function getGlobal(){
console.log(config);
}
Functions and variables are hoisted to the top of the parent function
// Hoisting - When false still "defined", even if not assigned
function itsIffy() {
if (false) {
var iffy = "whatev's";
}
console.log(iffy);
}
To fix this, use closures
// Functions can scope within functions
function outerScope(){
var closure;
function innerScope(){
closure = "I'm told I am in a closure?";
console.log(closure)
}
innerScope();
}
outerScope();
// shows closure is not on global scope
console.log(closure); // ERRRRORRR
Object Context
var o = {
x:10,
m: function(){
var x = 1;
console.log(x, this.x);
}
}
o.m();
What's the output?
New context
When you new up an object in JavaScript the constructor is passed a new context. This is simply object context in disguise.
var A = function(){
this.name = 'New';
};
var a = new A();
*What's **this**?*<!-- o -->
Global Context
The way JavaScript currently works is if a function doesn’t have context, or is not a method associated with an object, it executes in the global space. [1]
var o = {
x:10,
m: function(){
var x = 1;
var f = function(){
console.log(x, this.x);
}
f();
}
}
o.m();
What's the output?
What's this?
You could reference global object to get to x
//...
var f = function(){
console.log(x, o.x);
}
//...
But if you are in protptype function that may not be possible
var C = function(){};
C.prototype = {
x:10,
m: function(){
var x = 1;
var f = function(){
console.log(x, this.x);
}
f();
}
}
var instance1 = new C();
instance1.m();
Your first thought may be to break out f and attach it to the prototype
//...
m: function(){
var x = 1;
this.f();
},
f: function(){
console.log(x, this.x); // Reference ERROR!!
}
//...
But now there is a scoping issue
Attach the function to the object context
//...
m: function(){
var x = 1;
this.f = function(){
console.log(x, this.x); // outputs 1, 10
}
this.f();
}
//...
JavaScript provides the call and apply functions to call methods with a specified context
//...
m: function(){
var x = 1;
var f = function(){
console.log(x, this.x); // outputs 1, 10
}
f.call(this);
var args = [1,'a'];
f.apply(this, args);
}
//...
We commonly find nested functions used as callbacks. Be aware that anonymous functions receive the global context!
var o = {
x:10,
onTimeout: function(){
console.log("x:", this.x);
},
m: function(){
setTimeout(function(){
this.onTimeout(); // ERROR
}, 1);
}
}
o.m();
A common solution to this problem is to save off a reference to this
//...
m: function(){
var self = this;
setTimeout(function(){
self.onTimeout();
}, 1);
}
//...
Immediate Functions
// Some say module and immediate function are interchangable terms
(function(){
console.log("I get ran immidiately");
})();
// Small performance gain by passing in globals to closures
(function($){
console.log($);
})(jQuery);
// Do this thousands of times, woot!!
Returning or Exporting
// Returning Object Literals
var myModule = (function(){
var privateClosure = 0;
function voodoo(){
console.log("voodoo count: " + ++privateClosure);
// And I always return myself, when `new`
};
return {
voodoo: voodoo,
static: "Imma String, woopedy doo"
};
})();
// myModule is a singleton
myModule.voodoo();
myModule.voodoo();
myModule.voodoo();
// Returning Functions
var myModule = (function(){
function ImmaConstructor(){
console.log('I build stuff');
// And I always return myself, when `new`
};
return ImmaConstructor;
})();
new myModule();
Object literals are singleton object with attributes and methods.
It is an object that is itself an object instance, you cannot new
an
object literal.
// Object literals are evaluated immediatly
// This is important to note if you are using jQuery
function stringMe(){ return "string"; };
var literal = {
key: 'value',
method: function() {
console.log("imma function");
},
assignedImmediatlyAsString: stringMe()
};
console.log(literal.method());
console.log(literal['assignedImmediatlyAsString']);
console.log(literal['method']());
Every function in javascript returns something, even if that
something is undefined
.
function evenThoughIDontSpecifyReturnIReturnUndefined () {
console.log("look for undefined after me");
};
evenThoughIDontSpecifyReturnIReturnUndefined();
Constructor functions have a convention of starting with a capital letter.
// Never return anything from a constructor function
function ImmaConstructor() {
return {
bad: "idea",
my: "context",
was: "lost"
};
};
var ohNo = new ImmaConstructor();
console.log(ohNo);
You can tack things on to a new constructor instance
// This is horrible on memory, there is a better way
function ImmaConstructor() {
this.works = function () {console.log('this works')};
this.alsoWorks = function () {console.log('this also works')};
};
var imma = new ImmaConstructor();
imma.works();
imma.alsoWorks();
Prototypes cannot be changed once an object is instantiated, thus you cannot change the prototype of an object literal.
Prototypes have simple rules, look at instance, look at prototype, look at prototypes... up the chain.
var duck = {
quack: "quack",
goNorth: function() { this.fly(); }
}
var mallord = Object.create(duck);
mallord.fly = function() { console.log("flapping wings"); };
var fakeMallord = Object.create(mallord);
fakeMallord.fly = function() { console.log("I can't"); };
fakeMallord.goNorth();
// don't work
duck.goNorth();
Prototypes are shared
function Duck () {};
mallord = new Duck();
Duck.prototype.fly = function() {console.log("flapping wings"); }
mallord.fly();
// instances are not shared
rubberDuck = new Duck();
rubberDuck.fly = function(){console.log("I can't");};
rubberDuck.fly();
uglyDuck = new Duck();
uglyDuck.fly();
var Person = (function () {
// global shared by all people
var count = 0;
function Person (name) {
console.log(++count, "people");
// name only belongs to this instance
this.name = name;
};
Person.prototype = {
// sayHello is shared in memory by every person
sayHello: function () {
// even though the name belongs to the instance `this` allows
// access to the context
console.log("Hello, my name is " + this.name);
}
};
return Person;
})();
var m = new Person("Micah");
var c = new Person("Chase");
m.sayHello();
c.sayHello();