javascript functions

32
JavaScript Functions Colin DeCarlo

Upload: colin-decarlo

Post on 11-Aug-2015

177 views

Category:

Internet


0 download

TRANSCRIPT

JavaScript FunctionsColin DeCarlo

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?

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

How do I create these “functions”?

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'); } );})();

What happens when I invoke a function?

Execution Context

add(2, 3);

x: 2y: 3

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’

thiscontains a reference to some object

x: 2y: 3

add(2, 3); this: window

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);

}

Hoisting: One Simple RuleDon’t. Declare all variables and functions at the top.

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

How may I wield this power?

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