This document provides an introduction to JavaScript concepts such as variables, functions, objects, scopes, and inheritance. Some key points covered include:
- JavaScript variables can be declared with or without the var keyword, and variable types are dynamically determined.
- Functions are objects that can have properties and methods, create closures, and be stored in variables.
- Objects are collections of key-value pairs that use prototypical inheritance rather than classes. Constructors are functions used to create objects.
- Scope is determined lexically and created by functions, allowing private variables through closures. This and prototypes are used to implement inheritance and encapsulation.
- Primitives appear to have methods but actually
3. ● Object Oriented
● Dynamic and lose typed
● No classes, no interfaces, no
abstraction
● Prototypical inheritance
● No privacy control at object level
● Object as collection of properties
● Function scope
7. Let's create a variable
var name = "Let's JavaScript"; //string
var i = 1; //number ("integer")
var fl = 1.11; //number ("float")
var boo = true; //boolean
glob = "I'm global string";
13. Let's create a function
var f = function(arg) {
//function body
};
14.
15. Function in JavaScript
●
●
●
●
●
●
●
●
Is an object
Can have properties and methods
Is Closure
Reference can be stored in variable
Can create other functions
Have own scope
Have special property - prototype
Native methods bind, apply, call
16. So...
function hello() {
console.log('Hello world');
Looks like "normal" function declaration,
but in fact...
}
===
var hello = function() {
console.log('Hello world');
}
...it is translated to this form so
anonymous function is created and it's
reference is passed to var
===
var hello = new Function(
"console.log('Hello world')"
);
and what's more every function
declaration is creation of new object
17. Function arguments
● Are stored in pseudo-array arguments
● Primitives (number, string, boolean) are
always passed by value
● Objects are passed by reference
18. Function arguments
var test = function(a, b, obj) {
obj.modified = true;
console.log(arguments);
}
var obj = {};
console.log(obj.modified); //'undefined'
test(1, 'a', obj); //{ '0': 1, '1': 'a', '2': { modified: true } }
console.log(obj.modified); //true
It is object so was passed
by reference
19. Accumulator problem
Problem :
"I want to create accumulator function which
accumulates values passed to it"
Solution:
"In JavaScript, function is an object so I can
create function with internal variable handling
passed values sum"
20. How to do NOT use function
var accumulator = function(x) {
this.sum = (this.sum || 0) + x;
return this.sum;
}
console.log(accumulator(1)); //1
console.log(accumulator(1)); //2
console.log(accumulator.sum); //undefined
console.log(sum); //2
//whoups!
22. this IS NOT this
this by default refers to the object that a
function is a member of
{
var accumulator = function(x) {
this.sum = (this.sum || 0) + x;
return this.sum;
}
}
In this case, function is member of
default global object so this refers to
global object.
If we run this code in browser, global
object is window so this === window
23. Let’s try without this
var accumulator = function(x) {
accumulator.sum = (accumulator.sum || 0) + x;
return accumulator.sum;
}
Public, so someone can spoil our
internal state
Ok… but...
accumulator.sum = undefined;
accumulator(1); //returns NaN :(
26. Let's create a scope
var f = function() {
//new scope :)
};
looks familiar?
27. or in other way...
(function() {
//new scope
}());
28. JavaScript's scope
● Is static (lexical)
● Is created only by function
● Function arguments becomes part of
scope
● Child scope have reference to parent
scope (scope chain)
● this is not scope (!!!)
29. Function scope
var test = 'global scope var';
var f = function() {
var test = 'function f scope';
console.log(test);
}
Local test variable declaration,
covers global test variable
console.log(test); //returns 'global scope var'
f(); //returns 'function f scope'
30. Hidden scope reference
var test = 'global scope var';
var a = function() {
console.log(test);
}
var b = function(callback) {
var test = 'function b scope var';
callback();
}
b(a); //returns 'global scope var'
Function object
contains hidden
reference to scope in
which was created
31. Hidden scope reference
var test = 5;
var inc = function() {
return ++test;
}
var dec = function() {
return --test;
}
inc(); //returns 6
dec(); //returns 5 NOT 4
Both functions inc
and dec have
reference to common
scope so both can
modify the same
variable
32. Returning to accumulator problem
"Creator" function
var accumulator = (function() {
Initialize sum variable in
var sum = 0;
creator function's scope
return function(x) {
Adds x to parent scope's
sum += x;
variable sum
return sum;
};
})();
Immediate executing
Scope based privacy!
33.
34. Common scoping mistake
var callbacks = [];
for(var i = 0; i < 10; i++) {
callbacks[i] = function() {
console.log(i);
}
}
for(var index in callbacks) {
callbacks[index]();
}
35. Common scoping mistake
var callbacks = [];
for(var i = 0; i < 10; i++) {
callbacks[i] = function() {
console.log(i);
}
At the end of for loop, i === 10
}
for(var index in callbacks) {
callbacks[index]();
}
For loop doesn't create
new scope, so variable i is
global
Log global variable i
36. .bind for the rescue!
bind is Function object method which
creates new function with bounded
parameters
37. .bind for the rescue!
var log = function(x) {
console.log(x);
}
Object reference which
will be bound to this
variable in function
scope (It doesn't matter
in this case)
var logHello = log.bind(null, ”Hello”);
log(1); //prints 1
log(”test”); //prints test
logHello(); //prints Hello
Values which will be
bound to function’s
parameters
38. Common scoping mistake FIXED
var callbacks = [];
var logger = function(i) {
console.log(i);
}
Create local scope
variable i
Log logger function's
scope variable i
for(var i = 0; i < 10; i++) {
callbacks[i] = logger.bind(null, i);
}
Returns new function with bounded
global variable i value as function
argument
51. How new works
Have to be used with constructor
function
● Uses prototype function property
reference as __proto__ of new object
● Binds new object to constructor's this
● Executes constructor function
●
52. How new works
var HelloWorld = function(greetMsg) {
this.greetMsg = greetMsg;
Don't use return. New
object will be returned
automatically
}
HelloWorld.prototype.greet = function() {
console.log(this.greetMsg);
}
var hi = new HelloWorld('Hi!');
hi.greet();
We create our constructor
as new function object
this is binded to new object so
we declare object variable
greetMsg
We declare common object's
properties in constructor
function's prototype
53. How new works
HelloWorld.prototype
● greet
HelloWorld
● prototype
hi
●
__proto__
hello
● __proto__
*Imagine __proto__ is hidden reference (it is available in some browsers but It is not standard)
54. How new works
var HelloWorld = function(greetMsg) {
this.greetMsg = greetMsg;
Don't use return. New
object will be returned
automatically
}
HelloWorld.prototype.greet = function() {
console.log(this.greetMsg);
}
var hi = new HelloWorld('Hi!');
hi.greet();
console.log(hi.greetMsg); //returns 'Hi!'
We create our constructor
as new function object
this is binded to new object so
we declare object variable
greetMsg
We declare common object's
properties in constructor
function's prototype
55. Privacy problem - how to do NOT fix
var HelloWorld = function(greetMsg) {
}
HelloWorld.prototype.greet = function() {
console.log(greetMsg);
}
We would like to keep greetMsg
private. As we know, the only
way is to do it private in
constructor's scope
We are trying to get private
variable but it is different scope
which don't have access to
constructor's scope
var hi = new HelloWorld('Hi!');
hi.greet(); //ReferenceError: greetMsg is not defined
56. Privacy problem fix
var HelloWorld = function(greetMsg) {
this.greet = function() {
We creating greet function
inside constructor so it has
access to constructor's scope.
console.log(greetMsg);
}
}
Consider that it is not part of
prototype so we create new
function per object creation.
In JavaScript, memory is price
for privacy.
var hi = new HelloWorld('Hi!');
hi.greet();
console.log(hi.greetMsg); //returns 'undefined'
57. Forgotten new disaster
var HelloWorld = function(greetMsg) {
this.greetMsg = greetMsg;
}
this is binded to global object
so we declare global variable
greetMsg
HelloWorld.prototype.greet = function() {
console.log(this.greetMsg);
Prototype won't be used, so
we won't have greet method
}
Disaster begins here
var hi = HelloWorld('Hi!');
hi.greet(); //TypeError: Cannot call method 'greet' of undefined
console.log(greetMsg); //returns 'Hi!'
59. Classical inheritance
var Animal = function(name) {
this.name = name;
}
Animal.prototype.getName = function() {
return this.name;
}
var dolphin = new Animal('Dolphin');
dolphin.getName(); //returns 'Dolphin'
60. Classical inheritance
We want WalkingAnimal, which extends Animal and
adds method walk
var WalkingAnimal = function() {
}
We need constructor
function
WalkingAnimal.prototype = new Animal();
We have to set object we would like to extend as
constructor prototype.
Unfortunately we have to call constructor to create
object. We don't pass any arguments so name will be
undefined
61. Classical inheritance
var WalkingAnimal = function(name) {
We should not forget
Animal.call(this, name);
about calling Animal
constructor to do it's job
}
WalkingAnimal.prototype = new Animal();
WalkingAnimal.prototype.walk = function() {
console.log(this.getName() + 'is walking');
Next we add method walk
}
to WalkingAnimal
prototype
var cow = new WalkingAnimal('Cow');
cow.getName(); //returns 'Cow'
cow.walk(); //'Cow is walking'
63. Object.create*
var WalkingAnimal = function(name) {
Animal.call(this, name);
}
WalkingAnimal.prototype = Object.create(Animal.prototype);
WalkingAnimal.prototype.walk = function() {
console.log(this.getName() + ' is walking');
}
Object.create sets hidden __proto__
reference to Animal.prototype but
without calling constructor
*Introduced in JavaScript 1.6
64. inherits function to hide ugly stuff
Function.prototype.inherits = function(parent, methods) {
this.prototype = Object.create(parent.prototype);
We store parent in
this.prototype.$parent = parent;
$parent variable. Can
be useful later
for(name in methods) {
this.prototype[name] = methods[name];
}
}
We copy every method from methods
object to function prototype
66. Or maybe don't do it classical
●
●
●
●
●
Don't use new
Don't use prototype
Forgot about inheritance tree
Use composition and mixins
Use power of functions (including functional
programming)
● Treat objects like function namespace or data container
not state container
● Occasionally use Object.create and Object.
defineProperty if you need
67. References
●
Douglas Crockford "JavaScript: The good parts"
●
Douglas Crockford's site (http://www.crockford.com/)
●
Dymitry Soshnikov's blog (http://dmitrysoshnikov.com)
●
Mozilla's "A re-introduction to JavaScript" (https://developer.mozilla.org/enUS/docs/JavaScript/A_re-introduction_to_JavaScript?redirect=no)
●
Angus Croll's blog (http://javascriptweblog.wordpress.com)
71. JavaScript primitives with methods?
var a = 1;
console.log(typeof a); //returns 'number'
console.log(a instanceof Number); //returns false
console.log(a.toExponential()); //returns 1e+0
var b = "abc";
console.log(typeof b); //returns 'string'
console.log(b instanceof String); //returns false
console.log(b.slice(1)); //returns 'bc'
var c = true;
console.log(typeof c); //returns 'boolean'
console.log(c instanceof Boolean); //returns false
console.log(c.toString()); //returns 'true'
72. The secret life of primitives
var a = 1;
a.toExponential();
It is not really method
of primitive.
=
var a = 1;
(new Number(a)).toExponential();
Every time you trying access
primitive method, new object,
containing primitive value is
created secretly.