Saltar al contenido principal
Diving Deep into
JavaScript Functions
By: Colin DeCarlo
colindecarlo@colindecarlo
About Me
colindecarlo@colindecarlo
About Me
colindecarlo@colindecarlo
Colin DeCarlo
Software Developer
PHP & JavaScript
colindecarlo@colindecarlo
colindecarlo@colindecarlo
Why?
colindecarlo@colindecarlo
Other people need to know this
colindecarlo@colindecarlo
–Johnny Appleseed
“Type a quote here.”
colindecarlo@colindecarlo
–Johnny Appleseed
“Type a quote here.”
colindecarlo@colindecarlo
–Johnny Appleseed
“Type a quote here.”
colindecarlo@colindecarlo
Warning
This talk will be technical
colindecarlo@colindecarlo
Agenda
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?"
What is a JavaScript Function?
colindecarlo@colindecarlo
Functions are Objects
With properties, methods and a {{Prototype}}
Functions are Objects
With properties, methods and a {{Prototype}}
function add(x, y) {
return x + y;
}
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
How do I create these “functions”?
colindecarlo@colindecarlo
Named Function
function named_function() {
return "I'm a named function!"
}
Function Expression
var function_expression = function () {
return "I'm a function expression!";
}
Immediately Invoked Function Expression
(function () {
var button = document.getElementById(
'submit_button'
);
button.addEventListener('click',
function (e) {
this.classList.add('disabled');
}
);
})();
colindecarlo@colindecarlo
colindecarlo@colindecarlo
What happens when I invoke a
function?
colindecarlo@colindecarlo
add(2, 3);
add(2, 3);
Execution Context
add(2, 3);
Execution Context
scope chain
add(2, 3);
Execution Context
scope chain
Activation
Object
add(2, 3);
Execution Context
scope chain
Activation
Object
add(2, 3);
Execution Context
scope chain
Activation
Object
colindecarlo@colindecarlo
colindecarlo@colindecarlo
Scopes
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]
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
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
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
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
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
colindecarlo@colindecarlo
colindecarlo@colindecarlo
Activation Object
colindecarlo@colindecarlo
this
contains a reference to some object
add(2, 3); this: {{ object }}
var that = this;
colindecarlo@colindecarlo
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();
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
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();
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();
As element attributes
<button id="calculate" onmouseover="this.style['border-color'] = 'blue';">
Calculate
</button>
As element attributes
this === calculate;
// => true
<button id="calculate" onmouseover="this.style['border-color'] = 'blue';">
Calculate
</button>
Functions as event handlers
<script>
var calculate = document.getElementById('calculate');
calculate.addEventListener('click', function (e) {
this.innerHTML = 'Calculating...';
});
</script>
Functions as event handlers
this === calculate;
// => true
<script>
var calculate = document.getElementById('calculate');
calculate.addEventListener('click', function (e) {
this.innerHTML = 'Calculating...';
});
</script>
In a constructor function
function Circle(radius) {
this.radius = radius;
}
var myCircle = new Circle(42);
In a constructor function
this instanceof Circle;
// => true
function Circle(radius) {
this.radius = radius;
}
var myCircle = new Circle(42);
colindecarlo@colindecarlo
colindecarlo@colindecarlo
arguments
“Array like” object with numerical properties
this: window
add(2, 3);
arguments
“Array like” object with numerical properties
this: window
add(2, 3);
arguments: {
0: 2, 1: 3
}
Named Formal Parameters
this: window
add(2, 3); arguments: {
0: 2, 1: 3
}
Named Formal Parameters
this: window
add(2, 3); arguments: {
0: 2, 1: 3
}
x: 2
y: 3
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;
}
}
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;
}
}
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;
}
}
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));
}
Hoisting: One Simple Rule
colindecarlo@colindecarlo
Hoisting: One Simple Rule
colindecarlo@colindecarlo
Don’t. Declare all variables and functions at the top.
colindecarlo@colindecarlo
colindecarlo@colindecarlo
What happens when I invoke a
function?
colindecarlo@colindecarlo
What happens when I invoke a
function?
colindecarlo@colindecarlo
What happens when I invoke a
function?
colindecarlo@colindecarlo
• The Execution Context is created and placed on top of the execution stack
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
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
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
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
How may I wield this power?
colindecarlo@colindecarlo
Variadic Functions
var colors = enumer('RED', 'GREEN', ‘BLUE’),
selectedColor = ‘RED’;
colors.contains(selectedColor);
// => true
selectedColor = ‘YELLOW’;
colors.contains(selectedColor);
// => false
Variadic Functions
var colors = enumer('RED', 'GREEN', ‘BLUE’),
selectedColor = ‘RED’;
colors.contains(selectedColor);
// => true
selectedColor = ‘YELLOW’;
colors.contains(selectedColor);
// => false
function enumer() {
function contains (value) {
return this.hasOwnProperty(value);
}
var i, numValues = arguments.length,
values = {};
for (i = 0; i < numValues; i++) {
values[arguments[i]] = arguments[i];
}
values.contains = contains;
return values;
}
Variadic Functions
var colors = enumer('RED', 'GREEN', ‘BLUE’),
selectedColor = ‘RED’;
colors.contains(selectedColor);
// => true
selectedColor = ‘YELLOW’;
colors.contains(selectedColor);
// => false
function enumer() {
function contains (value) {
return this.hasOwnProperty(value);
}
var i, numValues = arguments.length,
values = {};
for (i = 0; i < numValues; i++) {
values[arguments[i]] = arguments[i];
}
values.contains = contains;
return values;
}
Variadic Functions
var colors = enumer('RED', 'GREEN', ‘BLUE’),
selectedColor = ‘RED’;
colors.contains(selectedColor);
// => true
selectedColor = ‘YELLOW’;
colors.contains(selectedColor);
// => false
function enumer() {
function contains (value) {
return this.hasOwnProperty(value);
}
var i, numValues = arguments.length,
values = {};
for (i = 0; i < numValues; i++) {
values[arguments[i]] = arguments[i];
}
values.contains = contains;
return values;
}
Variadic Functions
var colors = enumer('RED', 'GREEN', ‘BLUE’),
selectedColor = ‘RED’;
colors.contains(selectedColor);
// => true
selectedColor = ‘YELLOW’;
colors.contains(selectedColor);
// => false
function enumer() {
function contains (value) {
return this.hasOwnProperty(value);
}
var i, numValues = arguments.length,
values = {};
for (i = 0; i < numValues; i++) {
values[arguments[i]] = arguments[i];
}
values.contains = contains;
return values;
}
Variadic Functions
colindecarlo@colindecarlo
colindecarlo@colindecarlo
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
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
Modifying Context
Taking control of this
bind(thisArg, arg1, …, argN)
use to set the value of this but without executing the function
colindecarlo@colindecarlo
colindecarlo@colindecarlo
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;
}
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;
}
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
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
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
colindecarlo@colindecarlo
colindecarlo@colindecarlo
Closures
A function which “closes over” a variable from an outer scope
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
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
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