When we put the new
keyword infront of any funciton call, it turns the function call into a constructor
call
This isn't the same as a class
There are 4 things that happen when a new
keyword is put infront of a function call:
- An empty object is created
- The empty object gets linked to a different object
- empty object gets bound as
this
for the purpose of the function call - if the function does not otherwise return anything,
new
will insertreturn this
function foo() {
this.baz = "baz";
console.log(this.bar + " " + baz);
}
var bar = "bar";
var baz = new foo(); // the foo() function with a `baz` property
Here are the 4 questions to ask to determin this
binding:
- was the function called with
new
? if so, use that object - was it called with
call
orapply
? if so, use that object - was the function called with a containing/ owning object?
- default: global object
note The new
keyword can override hard bindings
- new
- explicit
- implicit
- default
How do you borrow a function through implicit assignment? object.method -- method gets object as this
explicit? call/apply
hard binding through .bind? Methods will always use the hard-bound this
reference
new
is a keyword.
Closure is when a function remembers its lexical scope even when the function is executed outside that lexical scope
function foo() {
var bar = "bar";
function baz() {
console.log(bar);
}
bam(baz);
}
function bam(baz) {
baz(); // "bar" <-- closure
}
foo();
function foo() {
var bar = "bar";
return function() {
console.log(bar);
}
}
function bam() {
foo()(); // "bar" <-- closure
}
bam();
function foo() {
var bar = "bar";
setTimeout(function() {
console.log(bar);
}, 1000);
}
foo();
function foo() {
var bar = 0;
setTimeout(function() {
console.log(bar++);
}, 100);
setTimeout(function() {
console.log(bar++);
}, 200);
}
foo(); // 0 1
It maintains the entire scope for as long and as deep as is necessary
function foo() {
var bar = 0;
setTimeout(function() {
var baz = 1;
console.log(bar++);
setTimeout(funciton() {
console.log(bar+baz);
}, 200);
},100);
}
foo(); // 0 2
Classical example: this prints out 6 5 different times
for (var i=1; i<=5; i++) {
setTimeout(function() {
console.log("i: " + i);
}, i*1000);
}
An IIFE can give us 5 different i values:
for (var i=1; i<=5; i++) {
(function(i){
setTimeout(function() {
console.log("i: " + i);
}, i*1000);
})(i);
}
What if we use let
?
for (let i=1; i<=5; i++) { // this creates a new `i` for each iteration
setTimeout(function() {
console.log("i: " + i);
}, i*1000);
}
Is this a closure? No, it's not a function
var foo = (function() {
var o = { bar: "bar" };
return { obj: o };
})();
console.log(foo.obj.bar); // bar
Classic module pattern:
var foo = (function() { // wrapped in an outer enclosing function
var o = { bar: "bar"};
return {
bar: function() { // returns atleast one or more inner function references
console.log(o.bar);
}
}
})();
foo.bar(); // "bar"
Here's another example:
var foo = (function(){
var publicAPI = {
bar: function(){
publicAPI.baz();
},
baz: function(){
console.log("baz");
}
};
return publicAPI; // by using a named object, we can modify methods at run-time
})();
foo.bar();
Modern module pattern: (define is our module library)
define("foo", function() {
var o = { bar: "bar" };
return {
bar: function() {
console.log(o.bar);
}
};
});
Future module pattern:
var o = {bar : "bar" };
export function bar() {
return o.bar;
}
----------
import bar from "foo";
bar(); // "bar"
module foo from "foo";
foo.bar(); // "bar"
-
What is a closure and how is it created? A closure is a function that remembers its lexical scope even if it's called from outside that scope. It's created when an inner function is transported outside the outer function.
-
how long does its scope stay around? For as long as someone has a reference to the scope
-
why doesn't a funciton callback inside a loop behave as expected? There wasn't a variable created per iteration. To solve this, we use either an IIFE or the
let
keyword. -
How do you use a closure to create an encapsulated module? An outer wrapping function that returns one or more inner functions. This allows us to have public/private APIs, but makes testing a little harder to test, because you can't test the implementation details (i.e. private methods). Another trade-off is that every time we create a new module, we're creating lots of extra copys of the module.
-
In this exercise, you will modify existing code for a simple note taking app. You will not add/remove functionality per se, but instead organize the code into a more proper module design and make it more flexible/reusable.
-
Using what you learned about closure and the module pattern, modify your previous code to wrap all the functionality up into a simple object (call it "NotesManager" or something appropriate), with a simple API, consisting of:
- an
init()
method, which you will call from the outside when jQuery'sdocument.ready
event is fired, and pass in the data from the "database". - a public method to add in notes "in bulk" after retrieval from the "database". hint: this can/should be called before you run the "init" method.
-
Make sure you have a "private" storage of the
notes
data list inside your module. Why is it a good idea to keep the data "private" inside the module? -
What do you notice about the structure of this code as it relates to the DOM access and the usage of jQuery? Would it make sense to "generalize" this code so that the module didn't have hardcoded into it the various DOM elements it would operate on? Explore how you would modify the code in this fashion. What are the benefits and tradeoffs?