Skip to content

Instantly share code, notes, and snippets.

@aaronshaf
Last active January 19, 2022 16:40
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aaronshaf/9917356 to your computer and use it in GitHub Desktop.
Save aaronshaf/9917356 to your computer and use it in GitHub Desktop.
A JavaScript Refresher

Credit: Some phraseology taken from MDN

Today we are going to walk through some JavaScript miscellany. Hopefully it causes some good discussion, and serves as a refresher. Please ask questions and make interesting comments!

April Fool's

0.1 + 0.2 === 0.3

Iffy’s

We will start with “immediately-invoked function expressions”, AKA IIFE, AKA iffy’s. Iffy's are useful because JavaScript provides function scoping. Without them, you might pollute the global scope. With them, we get some privacy. Let’s take a look.

var foo = 'abc';
(function() {
  var foo = '123';
}());
console.log(foo);
window.SOME_GLOBAL = 'abc';
var obj = {}:

(function(window) {
  window.SOME_GLOBAL = '123';
}(obj));
console.log(window.SOME_GLOBAL);

If I make a function and immediately invoke it, you will see that the variables inside of it neither foist outward, nor pollute globals.

Closures

Next, let us consider closures. Because nested functions retain access to variables in outer scope, we can use nested functions to lock in, or “close over” variables. Let’s take a look.

function outer(foo) {
  function inner() {
    foo++;
    console.log(foo);
  }
  return inner;
}
var myFunc = outer(1);
myFunc();
myFunc();
myFunc();

If I make an outer function that returns an inner function, and then I execute this returned function, you see that it remembers the environment that I originally gave it.

call vs. apply

Next, let us consider the call and apply methods on functions.

call takes the value of this, then a list of arguments. apply takes the value of this, and then an array of arguments. Perhaps the “a” in apply and the “a” in array will help you remember this. Let’s take a look.

function doSomething(foo,bar) {
  console.log(this,foo,bar);
}
doSomething.call(1,2,3);
doSomething.apply(1,[2,3]);

My “doSomething” function will log this, foo, and bar. If I call the function, you can see that this, foo, and bar are populated. I can change this to apply, put foo and bar in an array with the same results.

This is helpful when I want to use Array-functions on non-arrays. For example:

Array.prototype.forEach.call(document.querySelectorAll("a"), function(a) {
  console.log(a.href);
});

or

[].forEach.call(document.querySelectorAll("a"), function(a) {
  console.log(a.href);
});

Counterfeit arrays!

Object.defineProperty

Browsers that support ECMAScript 5 (IE9+) precise configuration of properties on an object.

A property is configurable "if the type of this property descriptor may be changed and if the property may be delete." (MDN)

If a property is enumerable it will show when doing for... in.

If a property is writable you can assign it with an assignment operater.

With defineProperty we can also set the property's value and a custom getter and setter.

Let's look at an example:

var obj = {};
Object.defineProperty(obj,'foo',{
  configurable: false,
  enumerable: false,
  get: function() {
    this.bar *= 10;
    return this.bar;
  },
  set: function(value) {
    this.bar = value * 10;
    return this.bar;
  }
});

You can define multiple properties at a time with Object.defineProperties(obj,properties), with properties being a hash of properties.

Object.create takes two arguments, the prototype and the properties object.

While class-based languages make a distinction between classes and instances of those classes, JavaScript simply has... objects. Objects in JavaScript are like parasites, however, since they can be attached to other objects from which to get initial properties.

for… in and hasOwnProperty

Capture vs bubble

A click event "event traverses twice; first it travels from the window down to the target element (called capture) and then it travels back up to the window again (called bubbling)." (MDN) Event handlers can either handle the capture or the bubble.

Let's take a look:

var element1 = document.getElementById('element1');
var element2 = document.getElementById('element2');

var useCapture = true; // default is false

element1.addEventListener('click', function() {
  alert('outer');
}, useCapture);

element2.addEventListener('click', function() {
  alert('inner');
});

Again: Bubbling is inner-to-outer. Capturing is outer-to-inner.

"use strict"

If you want to opt in to some ES5+ restrictions, put “use strict” at the top of your script or function. If at the top of your script, just be aware of potential concatenation woes.

Among other things, strict mode:

  • throws an error when attempting to delete an undeletable
  • prohibits with
  • forces use of explicit "var"
  • throws an error when upon duplicate property or argument names
  • forbids octal syntax (since a leading zero prefix changes a number's meaning)

Try cleaning up the following:

function doSomething() {
  "use strict";
  foo = 1;
  var obj = {
    bar: 'abc',
    bar: 'xyz'
  };
  010 === 10;
  with(obj) {
    bar = '123'
  }
  
  function test(a,a,b) {}
  console.log('woo hoo!');
}
doSomething();

Automatic semicolon insertion

* [The infernal semicolon](https://brendaneich.com/2012/04/the-infernal-semicolon/)
* [JavaScript Semicolon Insertion: Everything you need to know](http://inimino.org/~inimino/blog/javascript_semicolons)

Function declaration vs function expression

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