Slide 1

Slide 1 text

Scope and Closures in JavaScript

Slide 2

Slide 2 text

Scope and Closures Please ask me questions during the slides...

Slide 3

Slide 3 text

Scope Where you can and cannot access your variables.

Slide 4

Slide 4 text

The easy stuff... Global Scope

Slide 5

Slide 5 text

window.myVar = "My String"; (function () { alert(myVar); }()); Alert: "My String"

Slide 6

Slide 6 text

var myVar = "My String"; (function () { alert(window.myVar); }()); Alert: "My String"

Slide 7

Slide 7 text

(function () { window.myVar = "My String"; }()); alert(myVar); Alert: "My String"

Slide 8

Slide 8 text

this.myVar = "My String"; (function () { alert(myVar); }()); Alert: "My String"

Slide 9

Slide 9 text

var myVar = "My String"; (function () { alert(this.myVar); }()); Alert: "My String"

Slide 10

Slide 10 text

(function () { this.myVar = "My String"; }()); alert(myVar); Alert: "My String"

Slide 11

Slide 11 text

Still pretty simple... Local Scope

Slide 12

Slide 12 text

(function () { var myVar = "My String"; alert(myVar); }()); Alert: "My String"

Slide 13

Slide 13 text

(function () { var myVar = "My String"; (function () { myVar = "My String, Rewritten"; }()); alert(myVar); }()); Alert: "My String, Rewritten"

Slide 14

Slide 14 text

(function () { (function () { var myVar = "My String"; }()); alert(myVar); }());

Slide 15

Slide 15 text

(function () { (function () { var myVar = "My String"; }()); alert(myVar); }()); Alert: Undefined

Slide 16

Slide 16 text

(function () { var myVar = "My String"; var myFunction = function () { myVar = "The String, Rewritten"; }; alert(myVar); }());

Slide 17

Slide 17 text

(function () { var myVar = "My String"; var myFunction = function () { myVar = "The String, Rewritten"; }; alert(myVar); }()); Alert: "My String"

Slide 18

Slide 18 text

(function () { var myVar = "My String"; var myFunction = function () { myVar = "The String, Rewritten"; }; alert(myVar); myFunction(); }());

Slide 19

Slide 19 text

(function () { var myVar = "My String"; var myFunction = function () { myVar = "The String, Rewritten"; }; alert(myVar); myFunction(); }()); Alert: "My String"

Slide 20

Slide 20 text

(function () { var myVar = "My String"; var myFunction = function () { myVar = "The String, Rewritten"; }; myFunction(); alert(myVar); }());

Slide 21

Slide 21 text

(function () { var myVar = "My String"; var myFunction = function () { myVar = "The String, Rewritten"; }; myFunction(); alert(myVar); }()); Alert: "The String, Rewritten"

Slide 22

Slide 22 text

(function () { var myVar; for (var i = 1; i <= 20; ++i) { document.getElementById("el-" + i).addEventListener("click", function () { myVar = "String #" + i; alert(myVar); }, false); } }());

Slide 23

Slide 23 text

(function () { var myVar; for (var i = 1; i <= 20; ++i) { document.getElementById("el-" + i).addEventListener("click", function () { myVar = "String #" + i; alert(myVar); }, false); } }()); Click #20 > Alert: "String #20"

Slide 24

Slide 24 text

(function () { var myVar; for (var i = 1; i <= 20; ++i) { document.getElementById("el-" + i).addEventListener("click", function () { myVar = "String #" + i; alert(myVar); }, false); } }()); Click #10 > Alert: "String #20"

Slide 25

Slide 25 text

(function () { var myVar; for (var i = 1; i <= 20; ++i) { document.getElementById("el-" + i).addEventListener("click", function () { myVar = "String #" + i; alert(myVar); }, false); } }()); Click #1 > Alert: "String #20"

Slide 26

Slide 26 text

Well, it doesn't do what you'd expect But Scoping Hides A Dark Side

Slide 27

Slide 27 text

(function () { var myVar = "My String"; (function () { var myVar = "My String, Rewritten"; }()); }());

Slide 28

Slide 28 text

(function () { var myVar = "My String"; alert(myVar); (function () { var myVar = "My String, Rewritten"; }()); }());

Slide 29

Slide 29 text

(function () { var myVar = "My String"; alert(myVar); (function () { var myVar = "My String, Rewritten"; }()); }()); Alert: "My String"

Slide 30

Slide 30 text

(function () { var myVar = "My String"; (function () { alert(myVar); var myVar = "My String, Rewritten"; }()); }());

Slide 31

Slide 31 text

(function () { var myVar = "My String"; (function () { alert(myVar); var myVar = "My String, Rewritten"; }()); }()); Alert: Undefined

Slide 32

Slide 32 text

(function () { var myVar = "My String"; (function () { var myVar = "My String, Rewritten"; alert(myVar); }()); }());

Slide 33

Slide 33 text

(function () { var myVar = "My String"; (function () { var myVar = "My String, Rewritten"; alert(myVar); }()); }()); Alert: "My String, Rewritten"

Slide 34

Slide 34 text

(function () { var myVar = "My String"; (function () { var myVar = "My String, Rewritten"; }()); alert(myVar); }());

Slide 35

Slide 35 text

(function () { var myVar = "My String"; (function () { var myVar = "My String, Rewritten"; }()); alert(myVar); }()); Alert: "My String"

Slide 36

Slide 36 text

(function () { var myVar = "My String"; (function () { var myVar = "My String, Rewritten"; }()); (function () { alert(myVar); }()); }());

Slide 37

Slide 37 text

(function () { var myVar = "My String"; (function () { var myVar = "My String, Rewritten"; }()); (function () { alert(myVar); }()); }()); Alert: "My String"

Slide 38

Slide 38 text

(function () { var myVar = "My String"; (function () { var myVar = "My String, Rewritten"; }()); (function () { alert(myVar); }()); }());

Slide 39

Slide 39 text

Closures Closures retain a function's local variables when the function exits.

Slide 40

Slide 40 text

var Person = function () { var name = "Steve"; return { getName: function () { return name; }, setName: function (newName) { name = newName; } }; }; var personOne = new Person(); alert(personOne.name); Alert: Undefined

Slide 41

Slide 41 text

var Person = function () { var name = "Steve"; return { getName: function () { return name; }, setName: function (newName) { name = newName; } }; }; var personOne = new Person(); alert(personOne.getName()); Alert: "Steve"

Slide 42

Slide 42 text

var Person = function () { var name = "Steve"; return { getName: function () { return name; }, setName: function (newName) { name = newName; } }; }; var personOne = new Person(); personOne.setName("Rob"); var personTwo = new Person(); personTwo.setName("Hannah"); alert(personOne.getName()); Alert: "Rob"

Slide 43

Slide 43 text

var Person = function () { var name = "Steve"; return { getName: function () { return name; }, setName: function (newName) { name = newName; } }; }; var personOne = new Person(); personOne.setName("Rob"); var personTwo = new Person(); personTwo.setName("Hannah"); alert(personTwo.getName()); Alert: "Hannah"

Slide 44

Slide 44 text

Fun times Scope in Closures

Slide 45

Slide 45 text

var Person = function () { this.name = "Steve"; }; Person.prototype = { getName: function () { return name; }, setName: function (newName) { name = newName; } }; var personOne = new Person(); personOne.setName("Rob"); alert(personOne.getName()); Alert: "Rob"

Slide 46

Slide 46 text

var Person = function () { this.familyName = "Anderson"; }; Person.prototype = { setFamilyName: function (newFamilyName) { name = newFamilyName; }, mother: { firstName: "Susan", getFamilyName: function () { // ??? } } }; var personOne = new Person(); personOne.setFamilyName("Taylor");

Slide 47

Slide 47 text

var Person = function () { this.familyName = "Anderson"; }; Person.prototype = { setFamilyName: function (newFamilyName) { name = newFamilyName; }, mother: { firstName: "Susan", getFamilyName: function () { // ??? } } }; var personOne = new Person(); personOne.setFamilyName("Taylor");

Slide 48

Slide 48 text

Setting your own scope Call and Apply

Slide 49

Slide 49 text

var personOne = { name: "Steve" }; var personTwo = { name: "Hannah" }; var sayHello = function (aPerson) { alert("Hello " + aPerson.name + ", my name is " + this.name); }; sayHello.call(personOne, personTwo); Alert: "Hello Hannah, my name is Steve"

Slide 50

Slide 50 text

var personOne = { name: "Steve" }; var personTwo = { name: "Hannah" }; var sayHello = function (aPerson) { alert("Hello " + aPerson.name + ", my name is " + this.name); }; sayHello.call(personTwo, personOne); Alert: "Hello Steve, my name is Hannah"

Slide 51

Slide 51 text

var personOne = { name: "Steve" }; var personTwo = { name: "Hannah" }; var sayHello = function (aPerson) { alert("Hello " + aPerson.name + ", my name is " + this.name); }; sayHello.apply(personOne, [ personTwo ]); Alert: "Hello Hannah, my name is Steve"

Slide 52

Slide 52 text

var personOne = { name: "Steve" }; var personTwo = { name: "Hannah" }; var sayHello = function (aPerson) { alert("Hello " + aPerson.name + ", my name is " + this.name); }; sayHello.apply(personTwo, [ personOne ]); Alert: "Hello Steve, my name is Hannah"

Slide 53

Slide 53 text

A real world example Call and Apply

Slide 54

Slide 54 text

var Person = function () { this.name = "Steve"; }; Person.prototype = { sayDelayedHello: function (delay) { setTimeout(this.sayHello, delay); }, sayHello: function () { alert("Hello, my name is " + this.name); } }; var person = new Person(); person.sayDelayedHello(1000);

Slide 55

Slide 55 text

var Person = function () { this.name = "Steve"; }; Person.prototype = { sayDelayedHello: function (delay) { setTimeout(this.sayHello, delay); }, sayHello: function () { alert("Hello, my name is " + this.name); } }; var person = new Person(); person.sayDelayedHello(1000); Alert: "Hello, my name is "

Slide 56

Slide 56 text

var bind = function(callback, scope) { return function() { var args = Array.prototype.concat.call(arguments); callback.apply(scope, args); }; } var Person = function() { this.name = "Steve"; }; Person.prototype = { sayDelayedHello: function(delay) { setTimeout(bind(this.sayHello, this), delay); }, sayHello: function() { alert("Hello, my name is " + this.name); } }; var person = new Person(); person.sayDelayedHello(1000);

Slide 57

Slide 57 text

var bind = function(callback, scope) { return function() { var args = Array.prototype.concat.call(arguments); callback.apply(scope, args); }; } var Person = function() { this.name = "Steve"; }; Person.prototype = { sayDelayedHello: function(delay) { setTimeout(bind(this.sayHello, this), delay); }, sayHello: function() { alert("Hello, my name is " + this.name); } }; var person = new Person(); person.sayDelayedHello(1000); Alert: "Hello, my name is Steve"

Slide 58

Slide 58 text

Scope and Closures Thanks for listening

Slide 59

Slide 59 text

References •  http://robertnyman.com/2008/10/09/explaining-javascript-scope-and-closures/ •  http://trephine.org/t/index.php?title=JavaScript_call_and_apply •  Steve Webster & Daniel Brownridge – Thanks for the advice and putting up with my questions :)