Javascript has two very important chains
Prototype-chain
Scope-chain
Object-oriented programming in JS
Prototyping is how Javascript implements object oriented programming.
There is no such thing as a class in Javascript (even though there
is a "class" keyword in ES6).
How do you create objects in JS?
var LivingEntity = function(location){
this.x = location.x;
this.y = location.y;
this.z = location.z;
};
An object's constructor is defined as just a function.
It is then differentiated from normal methods by calling it
with the word "new" in front of it, thus constructing a new object.
Adding methods?
var dog = new LivingEntity({
x: 5,
y: 0,
z: 1
});
dog.moveWest = function(){
this.x--;
};
Don't do this!
Unnecessary anonymous functions!
Eventually the number of separate anonymous functions will cause
a memory leak in your environment.
LivingEntity.prototype.moveWest = function(){
this.x--;
}
Do this!
Takes advantage of the prototype chain!
The functions defined on the prototype chain
only exist once, and references to them are
passed around.
Prototype is an attribute of all functions, but is only useful
when defining it on a constructor. This is a virtual attribute,
but you can see the real prototype of an object by using "__proto__"
on an object, but this is not defined in the specs and can change.
The difference between foo.__proto__ and Foo.prototype is that
foo.__proto__ is the prototype of that object, whereas Foo.prototype
will be and is the prototype of all objects constructed with new Foo()
What is the prototype chain?
Each object has a prototype, even the object that exists in another
object's prototype attribute.
How do you inherit from a superclass
var Dragon = function(location){
LivingEntity.call(this, location);
this.canFly = true;
};
Dragon.prototype = Object.create(LivingEntity.prototype);
Dragon.prototype.constructor = Dragon;
Dragon.prototype.fly = function(y){
this.y += y;
};
var sparky = new Dragon({
x: 0,
y: 0,
z: 0
});
Function.call will execute that function, but replace the normal
"this" value with the provided value, and use any parameters
afterwards as parameters of the function.
Object.create creates an object with the prototype specified. This creates an object
with an identical prototype chain as if you just did new LivingEntity(), but none
of the code in the constructor is run, so it is preferred when creating an object
for the purposes of a prototype chain.
What does the prototype-chain look like?
sparky
sparky.__proto__
x, y, z, canFly
fly
sparky.__proto__.__proto__
sparky.__proto__.__proto__.__proto__
moveWest
create, toString, etc...
It is important to note that sparky doesn't have any
references to it's class's methods (fly in this case)
except through the prototype chain
What happens when I call a method on an object?
The object is checked, then the prototype chain
is traversed until that method is found.
Anonymous functions
The root of the problem: Functions have a state!
Functions in JavaScript are first class citizens, which means that
they can be passed around in variables. This also means that they can
be created whenever you want, not like in Java where objects all
come with functions initially. This is changing in Java with lambdas.
There are similar problems with Java and anonymous classes. However,
these do not give the ability for methods to have a state.
Closure
var helloStr = 'world';
var sayHello = function(name){
return function(){
console.log('Hello ' + name + '!');
}
}
var sayGreeting = sayHello(helloStr);
//woops, I meant to greet Bob
helloStr = 'Bob';
sayGreeting();
This is an example of accidentally capturing a variable
when you didn't mean to.
What about this?
for (var i = 0; i < 10; i++){
setTimeout(function(){
console.log(i);
}, 1000);
}
Output
10
10
10
10
10
10
10
10
10
10
Closure is when an object is captured by a function, and can be referenced
whenever that function is called in the future. This gets a lot of
people in trouble, becuase they don't expect it to happen. In this
first example, the string was captured by the function, in the second,
it was not captured, and so it is referencing "i" when it was already
at 10 in the future.
What is scope?
Javascript has function scope
If you think of a function is JavaScript as a state machine,
scope is that state. Methods in Java cannot keep
state without using the state of their owner object. Functions
in JavaScript have their own state independent of their owner
object, and this is called scope. But much like the prototype
chain, it's not easy to view scope, and there is no official
way to do it.
Scope Properties
{
_scope,
variables
}
Every function has a scope, and when not inside of any function, the
global scope applies. This is not an exact definition, as there is none,
but it is useful. The "_scope" variable points to the previous scope,
forming the scope chain. The "variables" variable is a map of all
the variables declared in this scope and their values,
including variables passed into the scope. Whenever a variable is declared
in the scope, it is added to the variables map. Whenever it is initialized
or modified, it's value is modified in the map.
How are closures related to the scope chain?
When a variable is used, the scope chain is traversed
to find the first time the variable was declared
The first time the variable appears in the scope chain is the
value that is used and modified if that variable is used or modified.
Re-declaring a variable is a way of separating it from its previous
existence in the scope chain.
In the "Hello Bob!" example, the function returned was using its
newly declared "name" variable, instead of the "helloStr" variable.
In the setTimeout example, all 10 of the newly created functions were
using their shared reference to i, which went up to 10 and then stayed
there. They do not have individual references to i.
Doing closure right
var logI = function(i){
return function(){
console.log(i);
}
};
for (var i = 0; i < 10; i++){
setTimeout(logI(i), 1000);
}
If you wanted to make the previous setTimeout example work,
you have to capture "i" for each new function. Also note that
i is now immutable within each result of logI. This is a way
of creating immutable private variables in JavaScript.
IIFE
Immediately Invoked Functional Expression
(function(global){
var privateVariable = 'No one can ever see me or change me';
global.getPrivateVariable = function(){
return privateVariable;
};
})(window);
Immediately Invoked Functional Expressions are a pattern in JavaScript
that allow variables and methods to be made private by declaring them
inside a scope. This is how jQuery and a lot of other libraries are
structured.
Passing in the window object allows specific parts of
the IIFE to be exported to the global namespace.