Answering FEE Interview Questions - Part 4: JS the 2rd

Previously: part 3 - csspart 4 - js #1

The number of JS questions in the Front-end Interview Questions repo is pretty extensive, so I’m going to break them up into several blorg posts. This is part 2 of my JS answers.

Q. Difference between: function Person(){}, var person = Person(), and var person = new Person()?

function Person(){} is a function declaration, creating a named function that can later be called via Person().

var person = Person() is executing the function named Person, and storing its return value in the variable named person.

var person = new Person() is creating an instance of the object (or class) Person via the constructor pattern. The new object will inherit Person's prototype.

Q. What's the difference between .call and .apply?

The main function of these two methods is to set the context of a function call, so that this assumes the identity of the object that is passed in. Here's what happens without it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function openBeverage() {
  this.open = true;
}
function drinkBeverage( type ) {
  if ( !this.open ) {
    throw 'You poke yourself in the eye with an unopened bottle';
  }

  this.type = type;
  return this.drink();
}
// no given context for this, it assumes window when not in strict mode
openBeverage();
drinkBeverage( 'whiskey' ); // error! this.drink is not a function!

Now let's give it some context:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
var obj = {
  open   : false,
  drink  : function() {
    if ( this.type == 'beer' ) {
      return this.guzzle();
    }
    else {
      return this.sip();
    }
  },
  guzzle : function() {
    return 'burp';
  },
  sip    : function() {
    return 'whiskey breath';
  }
};
// Uncaught: "You poke yourself in the eye with an unopened bottle
drinkBeverage.call( obj, 'beer' );
drinkBeverage.apply( obj, ['beer']);

// ok, let's open our bottle
openBeverage.call( obj );

// using .call(), we pass in csv of the necessary params
drinkBeverage.call( obj, 'beer' );

// using .apply(), we pass in a single array with our param values
drinkBeverage.apply( obj, ['whiskey']);

By passing in an object, our function now has a relevant value for this. The main difference now between .call() and .apply() is that .call() relies upon a list of parameters to be passed to the called function (e.g., .call( obj, param1, param2, param3)), and .apply() uses an array to send params, .apply( obj, [param1, param2, param3]).

Q. Explain Function.prototype.bind.

.bind() has a similarity with .call() and .apply(), in that it is used to pass in an object to give context to this within the bound function:

1
2
3
4
5
6
7
8
9
function compute() {
  return this.x + this.y;
}
compute(); // NaN, referencing x and y within the window scope
var obj = {
  x : 1,
  y : 2
};
compute.bind( obj )(); // calls it immediately, returns 3

If you notice when we called .bind(), we had to throw some parentheses on the end to immediately invoke the newly-bound function. Unlike .call() and .apply(), which immediately execute the function, .bind() returns a new function with the permanently-bound context for this.

Another cool feature is that you can apply partial parameters to a bound function:

1
2
3
4
5
6
7
8
function drink() {
  var args = Array.prototype.slice.call( arguments ),
      last = args.pop();
  return args.join(', ') + ', and ' + last;
}
// no need for context with this example
drink = drink.bind( null, '1 Bourbon', '1 Scotch' );
drink( '1 Beer' ); // '1 Bourbon, 1 Scotch, and 1 Beer'
Q. When would you use document.write()?

You...wouldn't? I honestly can't think of a reason to use it. It's slow, it's blocking, it can't be used after document load.

Q. What's the difference between feature detection, feature inference, and using the UA string?

UA sniffing is a pretty dated practice, where we'd look at the UA of the request and make decisions based upon what we detected. Usually it was to make up for something silly that IE was about to do.

Feature inference looks for the availability of some particular object or function, and then infers from its availability that something else is likely available:

1
2
3
4
5
6
if ( localStorage ) {
  sessionStorage.setItem( 'key', 'value' );
}
else {
  // no sessionStorage :'(
}

Feature detection is somewhat similar to inference in that it checks that an object or function exists before attempting to use it, but it's explicitly checking for that functionality, and not making assumptions beyond that. Feature detection is extremely useful for things like polyfills.

Q. Explain Ajax in as much detail as possible. What are the advantages and disadvantages of using Ajax?

Let's start with the acronym: Asynchronous Javascript and XML. It's a handy term used to describe making requests to the server (whether for creating or updating records, or modifying the UI) via the XMLHttpRequest() (XHR) API. This object allows the browser to asynchronously make a request and handle responses without requiring a full-page reload, leading to a faster and more responsive UI. Though XML is in the name, the response from the server can be anything: HTML, JSON, or even plaintext.

Advantages:
  • It's fast — many pages on a site share a chrome, so if you can fetch just the changing parts of a page you greatly limit the amount of data you're moving
  • It's responsive — meaning the results of a user's interaction typically appear quickly. This has given rise to the number of single-page apps that exist on the web today
Disadvantages:
  • History is trashed — the browser's default back/forward button functionality will not be present without additional work by the developer to support it. This will also affect a user's ability to bookmark pages or states in your app
  • Forms require both Ajax and non-Ajax support — JS breaks sometimes, and unless you want to block users from using your site, you need to support a full-page flow in addition to the Ajax flow
  • Same-origin policy — without some extra work on the front- and back-end, you will not be able to make any requests across domains
Q. Explain how JSONP works (and how it's not really Ajax).

JSONP is a clever way to work around the same-origin policy of XHR by appending dynamically-generated script tags to your DOM whose contents execute a global callback on your page and inject data.

First, you create a callback function on your page:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
window.cb = function( data ) {
  // we only want the data node of the returned blob
  data = data.data;

  // elements we'll be fooling with
  var img = document.createElement( 'img' ),
      txt = document.createElement( 'figcaption' ),
      fig = document.createElement( 'figure' );

  img.className = 'figure-img w-50 rounded';
  txt.className = 'figure-caption';
  fig.className = 'figure';

  // set the content of our new elements
  img.src = data.avatar_url;
  txt.innerHTML = data.name;

  // append them to our parent figure element
  fig.appendChild( img );
  fig.appendChild( txt );

  // insert the new element in the dom
  btn.parentNode.insertBefore( fig, btn );
};

Next we'll have an IIFE to contain our utility stuff:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(function() {
  var btn = document.getElementById( 'fetch-json' );
  btn.addEventListener( 'click', function() {
    btn.classList.add( 'disabled' );
    btn.setAttribute( 'disabled', true );

    // creates the dom node we'll insert
    var script = document.createElement( 'script' );
    script.setAttribute( 'id', 'json-script' );
    script.setAttribute( 'src', 'https://api.github.com/users/pacifisticuffs?callback=cb' );

    // add the new script to the page's head
    document.getElementsByTagName( 'head' )[0].appendChild( script );
  });
})();

We'll be hitting a fairly trustworthy API on Github that will retrieve my userdata and then pass it to the global function cb(), which will append a new image on the page. Go ahead and click!


As to why JSONP isn't Ajax, that has to do with the capabilities of both. Ajax allows us to perform all sorts of verbs on the server (HEAD, POST, GET etc.) and then gives us full access to the headers of the request and those returned with each response. JSONP on the other hand only allows us to GET from a remote server with no insight on the inner-workings of that request.

Q. Explain "hoisting".

Unlike languages like C, or C++, JS features function-level scoping instead of block-level scoping (or rather, it did, up until recently with let). This means that variables declared inside of loops (for (var x = 0; x < arr.length; x++) {} or if ( condition ) {} statements are available to their containing scope, whether that's a function or the window object.

Though scripts are interpreted top-to-bottom, JS prioritizes certain things over others. In particular, function and variable declarations are "hoisted" from their position in the script to the top of their containing scope. This can be confusing if you're expecting things to proceed in order.

1
2
3
4
5
6
blurt(); // logs undefined, then 'hork'
function blurt() {
  console.log( someVar );
  var someVar = 'hork';
  console.log( someVar );
}

Rather than encountering a reference error first, we got undefined instead. That's because JS reorders things a little bit inside the function:

1
2
3
4
5
6
7
8
9
function blurt() {
  var someVar; // the declaration is hoisted up to here
  console.log( someVar );
  someVar = 'hork'; // now it gets a value
  console.log( someVar );
}
// we can execute the function here because the function
// declaration is hoisted above
blurt(); // logs undefined, then 'hork'

The declaration occurs before the log, and the assignment happens afterward.

Q. What's the difference between an "attribute" and a "property"?

Attributes exist in your markup, and properties exist in your JS (they're HTMLElement object properties). The attribute values present in your markup provide the initial values for the object properties. Attributes are accessed via .getAttribute(). For example, element.getAttribute('value') or element.getAttribute('class'), whereas properties usually have the same or similar name, element.value or element.className

Q. Why is extending built-in JavaScript objects not a good idea?

This question is imposing its own opinion, but it's a valid concern. It's not always a bad idea when it's done safely. See every polyfill out there. What is a bad idea, particularly in multi-developer environments, is overwriting native functionality. Other developers might not be aware of what you've done, or your implementation may be buggy in some way.

Posted under: JS