Skip to content

Instantly share code, notes, and snippets.

@chadfurman
Last active January 31, 2017 13:43
Show Gist options
  • Save chadfurman/fa728beac8254202aa6719f52271655d to your computer and use it in GitHub Desktop.
Save chadfurman/fa728beac8254202aa6719f52271655d to your computer and use it in GitHub Desktop.
hour4

The new keyword

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:

  1. An empty object is created
  2. The empty object gets linked to a different object
  3. empty object gets bound as this for the purpose of the function call
  4. if the function does not otherwise return anything, new will insert return 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:

  1. was the function called with new? if so, use that object
  2. was it called with call or apply? if so, use that object
  3. was the function called with a containing/ owning object?
  4. default: global object

note The new keyword can override hard bindings

Quiz: this

  1. new
  2. explicit
  3. implicit
  4. 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.

Closures

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

Closure Examples

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

More Colsure Examples

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

Module Patterns

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"

Quiz: Closures

  1. 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.

  2. how long does its scope stay around? For as long as someone has a reference to the scope

  3. 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.

  4. 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.

Exercise 2

Instructions

  1. 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.

  2. 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's document.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.
  1. 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?

  2. 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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment