Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

JavaScript Functions

2,173 views

Published on

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.

Published in: Internet

JavaScript Functions

  1. 1. Diving Deep into JavaScript Functions By: Colin DeCarlo colindecarlo@colindecarlo
  2. 2. About Me colindecarlo@colindecarlo
  3. 3. About Me colindecarlo@colindecarlo Colin DeCarlo Software Developer PHP & JavaScript
  4. 4. colindecarlo@colindecarlo
  5. 5. colindecarlo@colindecarlo
  6. 6. Why? colindecarlo@colindecarlo
  7. 7. Other people need to know this colindecarlo@colindecarlo
  8. 8. –Johnny Appleseed “Type a quote here.” colindecarlo@colindecarlo
  9. 9. –Johnny Appleseed “Type a quote here.” colindecarlo@colindecarlo
  10. 10. –Johnny Appleseed “Type a quote here.” colindecarlo@colindecarlo
  11. 11. Warning This talk will be technical colindecarlo@colindecarlo
  12. 12. Agenda
  13. 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. 14. What is a JavaScript Function? colindecarlo@colindecarlo
  15. 15. Functions are Objects With properties, methods and a {{Prototype}}
  16. 16. Functions are Objects With properties, methods and a {{Prototype}} function add(x, y) { return x + y; }
  17. 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. 18. How do I create these “functions”? colindecarlo@colindecarlo
  19. 19. Named Function function named_function() { return "I'm a named function!" }
  20. 20. Function Expression var function_expression = function () { return "I'm a function expression!"; }
  21. 21. Immediately Invoked Function Expression (function () { var button = document.getElementById( 'submit_button' ); button.addEventListener('click', function (e) { this.classList.add('disabled'); } ); })();
  22. 22. colindecarlo@colindecarlo
  23. 23. colindecarlo@colindecarlo
  24. 24. What happens when I invoke a function? colindecarlo@colindecarlo
  25. 25. add(2, 3);
  26. 26. add(2, 3); Execution Context
  27. 27. add(2, 3); Execution Context scope chain
  28. 28. add(2, 3); Execution Context scope chain Activation Object
  29. 29. add(2, 3); Execution Context scope chain Activation Object
  30. 30. add(2, 3); Execution Context scope chain Activation Object
  31. 31. colindecarlo@colindecarlo
  32. 32. colindecarlo@colindecarlo
  33. 33. Scopes
  34. 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. 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. 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. 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. 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. 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
  40. 40. colindecarlo@colindecarlo
  41. 41. colindecarlo@colindecarlo
  42. 42. Activation Object colindecarlo@colindecarlo
  43. 43. this contains a reference to some object add(2, 3); this: {{ object }}
  44. 44. var that = this; colindecarlo@colindecarlo
  45. 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. 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. 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. 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. 49. As element attributes <button id="calculate" onmouseover="this.style['border-color'] = 'blue';"> Calculate </button>
  50. 50. As element attributes this === calculate; // => true <button id="calculate" onmouseover="this.style['border-color'] = 'blue';"> Calculate </button>
  51. 51. Functions as event handlers <script> var calculate = document.getElementById('calculate'); calculate.addEventListener('click', function (e) { this.innerHTML = 'Calculating...'; }); </script>
  52. 52. Functions as event handlers this === calculate; // => true <script> var calculate = document.getElementById('calculate'); calculate.addEventListener('click', function (e) { this.innerHTML = 'Calculating...'; }); </script>
  53. 53. In a constructor function function Circle(radius) { this.radius = radius; } var myCircle = new Circle(42);
  54. 54. In a constructor function this instanceof Circle; // => true function Circle(radius) { this.radius = radius; } var myCircle = new Circle(42);
  55. 55. colindecarlo@colindecarlo
  56. 56. colindecarlo@colindecarlo
  57. 57. arguments “Array like” object with numerical properties this: window add(2, 3);
  58. 58. arguments “Array like” object with numerical properties this: window add(2, 3); arguments: { 0: 2, 1: 3 }
  59. 59. Named Formal Parameters this: window add(2, 3); arguments: { 0: 2, 1: 3 }
  60. 60. Named Formal Parameters this: window add(2, 3); arguments: { 0: 2, 1: 3 } x: 2 y: 3
  61. 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. 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. 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. 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)); }
  65. 65. Hoisting: One Simple Rule colindecarlo@colindecarlo
  66. 66. Hoisting: One Simple Rule colindecarlo@colindecarlo Don’t. Declare all variables and functions at the top.
  67. 67. colindecarlo@colindecarlo
  68. 68. colindecarlo@colindecarlo
  69. 69. What happens when I invoke a function? colindecarlo@colindecarlo
  70. 70. What happens when I invoke a function? colindecarlo@colindecarlo
  71. 71. What happens when I invoke a function? colindecarlo@colindecarlo • The Execution Context is created and placed on top of the execution stack
  72. 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. 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. 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. 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. 76. How may I wield this power? colindecarlo@colindecarlo
  77. 77. Variadic Functions
  78. 78. var colors = enumer('RED', 'GREEN', ‘BLUE’), selectedColor = ‘RED’; colors.contains(selectedColor); // => true selectedColor = ‘YELLOW’; colors.contains(selectedColor); // => false Variadic Functions
  79. 79. 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
  80. 80. 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
  81. 81. 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
  82. 82. 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
  83. 83. colindecarlo@colindecarlo
  84. 84. colindecarlo@colindecarlo
  85. 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. 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. 87. Modifying Context Taking control of this bind(thisArg, arg1, …, argN) use to set the value of this but without executing the function
  88. 88. colindecarlo@colindecarlo
  89. 89. colindecarlo@colindecarlo
  90. 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. 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. 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. 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. 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
  95. 95. colindecarlo@colindecarlo
  96. 96. colindecarlo@colindecarlo
  97. 97. Closures A function which “closes over” a variable from an outer scope
  98. 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. 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. 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
  101. 101. colindecarlo@colindecarlo
  102. 102. colindecarlo@colindecarlo
  103. 103. Trick Question colindecarlo@colindecarlo
  104. 104. var funcs = []; for (var i = 0; i < 5; i++) { funcs.push(function () { console.log(i); }); } for (var j = 0; j < 5; j++) { funcs[j](); }
  105. 105. // => 5 // => 5 // => 5 // => 5 // => 5 var funcs = []; for (var i = 0; i < 5; i++) { funcs.push(function () { console.log(i); }); } for (var j = 0; j < 5; j++) { funcs[j](); }
  106. 106. // => 5 // => 5 // => 5 // => 5 // => 5 var funcs = []; for (var i = 0; i < 5; i++) { funcs.push(function () { console.log(i); }); } for (var j = 0; j < 5; j++) { funcs[j](); }
  107. 107. // => 0 // => 1 // => 2 // => 3 // => 4 var funcs = []; for (var i = 0; i < 5; i++) { funcs.push((function (i) { return function () { console.log(i); }; })(i)); } for (var j = 0; j < 5; j++) { funcs[j](); }
  108. 108. // => 0 // => 1 // => 2 // => 3 // => 4 var funcs = []; for (var i = 0; i < 5; i++) { funcs.push((function (i) { return function () { console.log(i); }; })(i)); } for (var j = 0; j < 5; j++) { funcs[j](); }
  109. 109. colindecarlo@colindecarlo
  110. 110. colindecarlo@colindecarlo
  111. 111. Encapsulation: A Better enumer
  112. 112. Encapsulation: A Better enumer var colors = enumer('RED', 'GREEN', 'BLUE'); colors.contains('RED'); // => true colors.contains('YELLOW'); // => 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; }
  113. 113. Encapsulation: A Better enumer var colors = enumer('RED', 'GREEN', 'BLUE'); colors.contains('RED'); // => true colors.contains('YELLOW'); // => false colors.YELLOW = 'YOLO'; colors.contains('YELLOW'); // => true 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; }
  114. 114. Encapsulation: A Better enumer var colors = enumer('RED', 'GREEN', 'BLUE'); colors.contains('RED'); // => true colors.contains('YELLOW'); // => false colors.YELLOW = 'YOLO'; colors.contains('YELLOW'); // => true delete colors.RED; colors.contains('RED'); // => 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; }
  115. 115. Encapsulation: A Better enumer var colors = enumer('RED', 'GREEN', 'BLUE'); colors.contains('RED'); // => true colors.contains('YELLOW'); // => false colors.YELLOW = 'YOLO'; colors.contains('YELLOW'); // => true colors.contains('contains'); // => true delete colors.RED; colors.contains('RED'); // => 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; }
  116. 116. Encapsulation: A Better enumer var colors = enumer('RED', 'GREEN', 'BLUE'); colors.contains('RED'); // => true colors.contains('YELLOW'); // => 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; }
  117. 117. Encapsulation: A Better enumer var colors = enumer('RED', 'GREEN', 'BLUE'); colors.contains('RED'); // => true colors.contains('YELLOW'); // => false function enumer() { var slice = Array.prototype.slice, values = slice.call(arguments, 0); return { contains: function (value) { return values.indexOf(value) >= 0; } }; }
  118. 118. Encapsulation: A Better enumer var colors = enumer('RED', 'GREEN', 'BLUE'); colors.contains('RED'); // => true colors.contains('YELLOW'); // => false colors.YELLOW = 'YOLO'; colors.contains('YELLOW'); // => false delete colors.RED; colors.contains('RED'); // => true function enumer() { var slice = Array.prototype.slice, values = slice.call(arguments, 0); return { contains: function (value) { return values.indexOf(value) >= 0; } }; }
  119. 119. Encapsulation: A Better enumer var colors = enumer('RED', 'GREEN', 'BLUE'); colors.contains('RED'); // => true colors.contains('YELLOW'); // => false colors.YELLOW = 'YOLO'; colors.contains('YELLOW'); // => false delete colors.RED; colors.contains('RED'); // => true colors.contains('contains'); // => false function enumer() { var slice = Array.prototype.slice, values = slice.call(arguments, 0); return { contains: function (value) { return values.indexOf(value) >= 0; } }; }
  120. 120. colindecarlo@colindecarlo
  121. 121. colindecarlo@colindecarlo
  122. 122. colindecarlo@colindecarlo Questions? https://joind.in/15748
  123. 123. colindecarlo@colindecarlo Questions? https://joind.in/15748
  124. 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); } };
  125. 125. Modifying Context Taking control of this
  126. 126. Modifying Context Taking control of this `call` `apply` `bind`
  127. 127. Modifying Context Taking control of this `call` `apply` `bind`
  128. 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. 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. 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
  131. 131. Modifying Context Taking control of this
  132. 132. Modifying Context Taking control of this `call` `apply` `bind`
  133. 133. Modifying Context Taking control of this `call` `apply` `bind`
  134. 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. 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. 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
  137. 137. Trick Question colindecarlo@colindecarlo
  138. 138. 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();
  139. 139. 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();
  140. 140. 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();
  141. 141. 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();
  142. 142. 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();
  143. 143. 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); }
  144. 144. Encapsulation the JavaScript Way
  145. 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. 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. 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

×