javascript functions
TRANSCRIPT
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?"
Functions are ObjectsWith properties, methods and a {{Prototype}}
function add(x, y) { return x + y;}
Own Properties Inherited Methods
name: add
length: 2
Function.prototypecall apply bind
Object.prototypetoString
Named Functions function named_function() { return "I'm a named function!"}
Function Expressions var function_expression = function () { return "I'm a function expression!";}
Immediately Invoked FunctionExpression
(function () { var button = document.getElementById( 'submit_button' );
button.addEventListener('click', function (e) { this.classList.add('disabled'); } );})();
Scopesvar globalVar = 'found in global context';
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); }
innner_function();}
global_function();
// => found in global context, found in global_function, found in inner_function// => undefined
global context
globalVar: ‘found in global context’global_function: [Function]
global_function context
localVar: ‘found in global_function’inner_function: [Function]
inner_functon context
innerVar: ‘found in inner_function’
thisdebug = true;
function something_complicated() {
if (this.debug) { console.log('Starting something_complicated'); }
// ... return complex_result;}
this === window;// => true
this
this === calculator;// => true
var caclulator = {
debug: true,
something_complicated: function () {
if (this.debug) { console.log('Starting something_complicated'); }
// ... return complex_result; }};
this
this === calculate;// => true
<button id="calculate" onmouseover="this.style['border-color'] = 'blue';"> Calculate</button>
<script> var calculate = document.getElementById('calculate');
calculate.addEventListener('click', function (e) { this.innerHTML = 'Calculating...'; });</script>
this
this instanceof Circle;// => true
function Circle(radius) { this.radius = radius;}
var myCircle = new Circle(42);
arguments‘Array like’ object with numerical properties
this: windowx: 2y: 3
add(2, 3);arguments: {
0: 2, 1: 3}
function enumer() { function contains(value) { return this.hasOwnProperty(value); }
var values = {}, numValues = arguments.length, i;
for (i = 0; i < numValues; i++) { values[arguments[i]] = arguments[i]; }
values.contains = contains;
return values;}
var colors = enumer('RED', 'GREEN', 'BLUE');
colors.contains('RED');// => true
colors.contains('YELLOW');// => false
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; }}
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));}
function getEventListener(sniffer) { function on(event, callback) { window.addEventListener(event, callback); }
if (sniffer.isIE()) { function on(event, callback) { window.attachEvent(event, callback); } }
return on; }
var browserSniffer = { isIE: function () { return false; } };
getEventListener(browserSniffer).toString();
function on(event, callback) {window.attachEvent(event, callback);
}
What happens when I invoke a function?
• The Execution Context is created and linked into the scope chain• `this` and `arguments` are declared and assigned• Named formal parameters are declared and assigned• Named functions are declared• Local variables are declared
Modifying ContextTaking 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
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;}
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); }};
Currying
function add(x, y) { return x + y;}
var plus42 = add.bind(void 0, 42);
plus42(42);
// => 84
Closures
function plusX(x) { return function(n) { return n + x; };}
var plus42 = plusX(42);
plus42(1);// => 43
A function which “closes over” a variable from an outer context
`x` as ’42’ is closed over in the anonymous function
the execution context of `plusX` is not destroyed because `plus42` still contains a reference to it in its scope chain
var i, j, funcs = [];
for (i = 0; i < 5; i++) { funcs.push(function () { console.log(i); });}
for (j = 0; j < funcs.length; j++) { funcs[j]();}
// => 5// => 5// => 5// => 5// => 5
// => 0// => 1// => 2// => 3// => 4
var i, j, funcs = [];
for (i = 0; i < 5; i++) { funcs.push((function (ii) { return function () { console.log(ii); }; })(i));}
for (j = 0; j < funcs.length; j++) { funcs[j]();}
Encapsulation the JavaScript Wayfunction 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]; };}
$ node encapsulation.jsvar v = new Vault('sekret');v.isLocked();truev.unlock('sekret')v.store('js_functions', 'Awesome')v.retrieve(‘js_functions')Awesomev.lock()v.isLocked()truev.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