Functions being first-class citizens in JavaScript offers developers a tremendous amount power and
flexibilty. However, what good is all this power if you don't know how to harness it?
This talk will provide a thorough examination of JavaScript functions. Topics
that will be covered in this talk are:
* Functions are objects
* Execution Context and the Scope Chain
* Closures
* Modifying Context
* The Various Forms of Functions.
Attendees will leave this talk understanding the power of JavaScript functions and the knowledge to apply new
techiques that will make their JavaScript cleaner, leaner and more maintainable.
13. Agenda
(function printAgenda() {
var topics = [
'What is a Function?',
'How do I create these "functions"?',
'What happens when I invoke a Function?',
'How do I wield this power?'
];
return topics.join("n");
})();
// => 'What is a Function?',
// => 'How do I create these "functions"?,
// => 'What happens when I invoke a Function?',
// => 'How do I wield this power?"
14. What is a JavaScript Function?
colindecarlo@colindecarlo
17. Functions are Objects
With properties, methods and a {{Prototype}}
function add(x, y) {
return x + y;
}
Own Properties Inherited Methods
name: add
length: 2
Function.prototype
call
apply
bind
Object.prototype
toString
18. How do I create these “functions”?
colindecarlo@colindecarlo
34. Scopes
var globalVar = 'found in global scope';
function global_function() {
var localVar = 'found in global_function';
function inner_function() {
var innerVar = 'found in inner_function';
console.log(globalVar, localVar, innerVar);
console.log(notFoundAnywhere);
}
inner_function();
}
global_function();
global scope
globalVar: ‘found in global scope’
global_function: [Function]
35. Scopes
var globalVar = 'found in global scope';
function global_function() {
var localVar = 'found in global_function';
function inner_function() {
var innerVar = 'found in inner_function';
console.log(globalVar, localVar, innerVar);
console.log(notFoundAnywhere);
}
inner_function();
}
global_function();
global scope
globalVar: ‘found in global scope’
global_function: [Function]
global_function scope
36. Scopes
var globalVar = 'found in global scope';
function global_function() {
var localVar = 'found in global_function';
function inner_function() {
var innerVar = 'found in inner_function';
console.log(globalVar, localVar, innerVar);
console.log(notFoundAnywhere);
}
inner_function();
}
global_function();
global scope
globalVar: ‘found in global scope’
global_function: [Function]
localVar: ‘found in global_function’
inner_function: [Function]
global_function scope
37. Scopes
var globalVar = 'found in global scope';
function global_function() {
var localVar = 'found in global_function';
function inner_function() {
var innerVar = 'found in inner_function';
console.log(globalVar, localVar, innerVar);
console.log(notFoundAnywhere);
}
inner_function();
}
global_function();
global scope
globalVar: ‘found in global scope’
global_function: [Function]
localVar: ‘found in global_function’
inner_function: [Function]
global_function scope
inner_functon scope
38. Scopes
var globalVar = 'found in global scope';
function global_function() {
var localVar = 'found in global_function';
function inner_function() {
var innerVar = 'found in inner_function';
console.log(globalVar, localVar, innerVar);
console.log(notFoundAnywhere);
}
inner_function();
}
global_function();
global scope
globalVar: ‘found in global scope’
global_function: [Function]
localVar: ‘found in global_function’
inner_function: [Function]
innerVar: ‘found in inner_function’
global_function scope
inner_functon scope
39. Scopes
var globalVar = 'found in global scope';
function global_function() {
var localVar = 'found in global_function';
function inner_function() {
var innerVar = 'found in inner_function';
console.log(globalVar, localVar, innerVar);
console.log(notFoundAnywhere);
}
inner_function();
}
global_function();
// => found in global scope, found in global_function, found in inner_function
// => undefined
global scope
globalVar: ‘found in global scope’
global_function: [Function]
localVar: ‘found in global_function’
inner_function: [Function]
innerVar: ‘found in inner_function’
global_function scope
inner_functon scope
45. A function which is simply executed
var debug = true;
function something_complicated() {
if (this.debug) {
console.log('Starting something_complicated');
}
// ...
return complex_result;
}
something_complicated();
46. A function which is simply executed
var debug = true;
function something_complicated() {
if (this.debug) {
console.log('Starting something_complicated');
}
// ...
return complex_result;
}
something_complicated();
this === window;
// => true
47. Functions as object properties
var calculator = {
debug: true,
something_complicated: function () {
if (this.debug) {
console.log('Starting something_complicated');
}
// ...
return complex_result;
}
};
calculator.something_complicated();
48. Functions as object properties
this === calculator;
// => true
var calculator = {
debug: true,
something_complicated: function () {
if (this.debug) {
console.log('Starting something_complicated');
}
// ...
return complex_result;
}
};
calculator.something_complicated();
49. As element attributes
<button id="calculate" onmouseover="this.style['border-color'] = 'blue';">
Calculate
</button>
50. As element attributes
this === calculate;
// => true
<button id="calculate" onmouseover="this.style['border-color'] = 'blue';">
Calculate
</button>
51. Functions as event handlers
<script>
var calculate = document.getElementById('calculate');
calculate.addEventListener('click', function (e) {
this.innerHTML = 'Calculating...';
});
</script>
52. Functions as event handlers
this === calculate;
// => true
<script>
var calculate = document.getElementById('calculate');
calculate.addEventListener('click', function (e) {
this.innerHTML = 'Calculating...';
});
</script>
53. In a constructor function
function Circle(radius) {
this.radius = radius;
}
var myCircle = new Circle(42);
54. In a constructor function
this instanceof Circle;
// => true
function Circle(radius) {
this.radius = radius;
}
var myCircle = new Circle(42);
61. Declaration and Hoisting
function concat() {
return " ".join(to_array(arguments));
function to_array(args) {
var words = [];
for (var i = 0; i < args.length; i++) {
words.push(args[i]);
}
return words;
}
}
62. Declaration and Hoisting
functions are declared
function concat() {
return " ".join(to_array(arguments));
function to_array(args) {
var words = [];
for (var i = 0; i < args.length; i++) {
words.push(args[i]);
}
return words;
}
}
63. Declaration and Hoisting
functions are declared
variables are declared
function concat() {
return " ".join(to_array(arguments));
function to_array(args) {
var words = [];
for (var i = 0; i < args.length; i++) {
words.push(args[i]);
}
return words;
}
}
64. Declaration and Hoisting
function concat() {
return " ".join(to_array(arguments));
function to_array(args) {
var words = [];
for (var i = 0; i < args.length; i++) {
words.push(args[i]);
}
return words;
}
}
function concat() {
function to_array(args) {
var words = [],
i;
for (i = 0; i < args.length; i++) {
words.push(args[i]);
}
return words;
}
return " ".join(to_array(arguments));
}
71. What happens when I invoke a
function?
colindecarlo@colindecarlo
• The Execution Context is created and placed on top of the execution stack
72. What happens when I invoke a
function?
colindecarlo@colindecarlo
• The Execution Context is created and placed on top of the execution stack
• this and arguments are declared and assigned
73. What happens when I invoke a
function?
colindecarlo@colindecarlo
• The Execution Context is created and placed on top of the execution stack
• this and arguments are declared and assigned
• Named formal parameters are declared and assigned
74. What happens when I invoke a
function?
colindecarlo@colindecarlo
• The Execution Context is created and placed on top of the execution stack
• this and arguments are declared and assigned
• Named formal parameters are declared and assigned
• Named functions are declared
75. What happens when I invoke a
function?
colindecarlo@colindecarlo
• The Execution Context is created and placed on top of the execution stack
• this and arguments are declared and assigned
• Named formal parameters are declared and assigned
• Named functions are declared
• Local variables are declared
76. How may I wield this power?
colindecarlo@colindecarlo
85. Modifying Context
Taking control of this
call(thisArg, arg1, …, argN)
use to set the value of this when you know the number
of arguments and what they are
86. Modifying Context
Taking control of this
apply(thisArg, argsArray)
use to set the value of this when you don’t know the number
of arguments
87. Modifying Context
Taking control of this
bind(thisArg, arg1, …, argN)
use to set the value of this but without executing the function
90. function memoize(func, context) {
var results = {},
wrapper = function () {
var args = Array.prototype.slice.call(arguments, 0),
key = ':'.join(args);
if (!results.hasOwnProperty(key)) {
results[key] = func.apply(context, args);
}
return results[key];
};
return wrapper;
}
91. function memoize(func, context) {
var results = {},
wrapper = function () {
var args = Array.prototype.slice.call(arguments, 0),
key = ':'.join(args);
if (!results.hasOwnProperty(key)) {
results[key] = func.apply(context, args);
}
return results[key];
};
return wrapper;
}
92. Partial Application with bind
the process of taking a function which accepts N arguments and turning it
into a function which accepts N - x arguments
93. Partial Application with bind
function add(x, y) {
return x + y;
}
var plus42 = add.bind(undefined, 42);
plus42(42);
the process of taking a function which accepts N arguments and turning it
into a function which accepts N - x arguments
94. Partial Application with bind
function add(x, y) {
return x + y;
}
var plus42 = add.bind(undefined, 42);
plus42(42);
// => 84
the process of taking a function which accepts N arguments and turning it
into a function which accepts N - x arguments
98. Closures
A function which holds a reference to another function’s Activation Object
thus allowing that function to access variables and functions defined
within it
99. Closures
function plusX(x) {
return function(n) {
return n + x;
};
}
A function which holds a reference to another function’s Activation Object
thus allowing that function to access variables and functions defined
within it
100. Closures
function plusX(x) {
return function(n) {
return n + x;
};
}
var plus42 = plusX(42);
plus42(1);
// => 43
A function which holds a reference to another function’s Activation Object
thus allowing that function to access variables and functions defined
within it
124. var someObject = Class.extend({
init: function () {
$('.some-selector').on('click', this.onClick.bind(this));
},
onClick: function (e) {
var result = this.helperFunction();
return this.format(result);
}
};
128. Modifying Context
Taking control of this
`call`
`apply`
`bind`
use to set the value of `this` when you know the number
of arguments and what they are
129. Modifying Context
Taking control of this
`call`
`apply`
`bind`
use to set the value of `this` when you know the number
of arguments and what they are
use to set the value of `this` when you don’t know the
number of arguments
130. Modifying Context
Taking control of this
`call`
`apply`
`bind`
use to set the value of `this` when you know the number
of arguments and what they are
use to set the value of `this` when you don’t know the
number of arguments
use to set the value of `this` but without executing the
function
134. Modifying Context
Taking control of this
`call`
`apply`
`bind`
use to set the value of `this` when you know the number
of arguments and what they are
135. Modifying Context
Taking control of this
`call`
`apply`
`bind`
use to set the value of `this` when you know the number
of arguments and what they are
use to set the value of `this` when you don’t know the
number of arguments
136. Modifying Context
Taking control of this
`call`
`apply`
`bind`
use to set the value of `this` when you know the number
of arguments and what they are
use to set the value of `this` when you don’t know the
number of arguments
use to set the value of `this` but without executing the
function
145. Encapsulation the JavaScript Way
function Vault(passcode) {
var locked = true,
data = {};
function checkPasscode(attemptedPasscode) {
return attemptedPasscode == passcode;
}
function grantAccess() {
locked = false;
return true;
}
this.isLocked = function () {
return locked;
};
this.lock = function () {
locked = true;
};
// ...
146. Encapsulation the JavaScript Way
function Vault(passcode) {
var locked = true,
data = {};
function checkPasscode(attemptedPasscode) {
return attemptedPasscode == passcode;
}
function grantAccess() {
locked = false;
return true;
}
this.isLocked = function () {
return locked;
};
this.lock = function () {
locked = true;
};
// ...
// ...
this.unlock = function (attemptedPasscode) {
checkPasscode(attemptedPasscode) && grantAccess();
};
this.store = function (key, value) {
if (this.isLocked()) {
throw new Error('The vault is locked');
}
data[key] = value;
};
this.retrieve = function (key) {
if (this.isLocked) {
throw new Error('The vault is locked');
}
return data[key];
};
}
147. $ node encapsulation.js
var v = new Vault('sekret');
v.isLocked();
true
v.unlock('sekret')
v.store('js_functions', 'Awesome')
v.retrieve(‘js_functions')
Awesome
v.lock()
v.isLocked()
true
v.retrieve('js_functions')
/Users/colin/Documents/talks/js_functions/encapsulation.js:40
throw new Error('The vault is locked');
^
Error: The vault is locked
at Vault.retrieve (/Users/colin/Documents/talks/js_functions/encapsulation.js:40:19)
at Object.<anonymous> (/Users/colin/Documents/talks/js_functions/encapsulation.js:68:3)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Function.Module.runMain (module.js:497:10)
at startup (node.js:119:16)
at node.js:906:3