DEV Community

John Au-Yeung
John Au-Yeung

Posted on • Originally published at thewebdev.info

JavaScript Interview Questions — Functions and Scope

Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62

Subscribe to my email list now at http://jauyeung.net/subscribe/

To get a job as a front end developer, we need to nail the coding interview.

In this article, we’ll look at some basic functions and scope questions.

What is Hoisting?

Hoisting means that a variable or function is moved to the top of their scope of where we defined the variable or function.

JavaScripts moves function declarations to the top of their scope of we can reference them later and gets all variable declarations and give them the value of undefined .

During execution, the variables that were hoisted are assigned a value or runs functions.

Only function declarations and variables declared with the var keyword are hoisted.

Variables declared with let and const constants aren’t hoisted. Also, arrow functions and function expressions aren’t hoisted.

For example, the following code has a function that’s hoisted:

foo();

function foo(){
 console.log('foo')
}
Enter fullscreen mode Exit fullscreen mode

foo is hoisted, so it can be called before it’s defined since it’s a function declaration.

The following variable declaration is hoisted:

console.log(x);
var x = 1;
console.log(x);
Enter fullscreen mode Exit fullscreen mode

The first console.log outputs undefined since var x is hoisted.

Then when var x = 1 runs, x is set to 1. Then we get 1 logged in the second console.log since x has its value set before it.

Anything else isn’t hoisted.

What is Scope?

JavaScript’s scope is the area where we have valid access to a variable or function.

There’re 3 kinds of scopes in JavaScript — global, function, and block scope.

Variables and functions that have global scope are accessible everywhere in the script or module file.

For example, we can declare a variable with global scope as follows:

var global = 'global';

const foo = () => {
  console.log(global);
  const bar = () => {
    console.log(global);
  }
  bar();
}
foo();
Enter fullscreen mode Exit fullscreen mode

Since we declared a variable with var on top of the code, it’s accessible everywhere. So both console.log s will output 'global' .

Function scoped variables are only available inside a function.

We can define a function scoped variable as follows:

const foo = () => {
  var fooString = 'foo';
  console.log(fooString);
  const bar = () => {
    console.log(fooString);
  }
  bar();
}
foo();

console.log(fooString);
Enter fullscreen mode Exit fullscreen mode

In the code above, we have the function scoped variable fooString . It’s also declared with var and it’s available inside both the foo function and the nested bar function.

Therefore, we’ll get ‘foo’ logged with the 2 console.log statements inside the foo function.

The console.log at the bottom gives us an error because function scoped variables aren’t available outside a function.

Block scoped variables are only available inside a block. That is, inside an if block, function block, loop, or an explicitly defined block. Anything delimited by curly braces is a block.

They’re defined either with let or const depending if it’s variable or constant.

For instance, if we write:

if (true) {
  let x = 1;
  console.log(x);
}

console.log(x);
Enter fullscreen mode Exit fullscreen mode

Then x is only available inside the if block. The console.log at the bottom gives us an x is not defined error.

Likewise, if we have had a loop:

for (let i = 0; i <= 1; i++) {
  let x = 1;
  console.log(x);
}

console.log(x);
Enter fullscreen mode Exit fullscreen mode

Then x is only available inside the loop. The console.log at the bottom gives us an x is not defined error.

We can also define a block explicitly just to isolate variables from the outside:

{
  let x = 1;
  console.log(x);
}

console.log(x);
Enter fullscreen mode Exit fullscreen mode

x will then only be available inside the curly braces. The bottom console.log will give us an error.

The scope determines how far the JavaScript will go to look for a variable. If it’s doesn’t exist in the current scope then it’ll look in the outer scope.

If it finds it in the outer scope and it’s declared in a way that we can access the variable then it’ll pick up that value.

Otherwise, if it’s not found, then we get an error.

What are Closures?

Closures are functions that remember the variables and parameters on its current scope and all the way up to the global scope.

In JavaScript, when an inner function has made available to any scope outside the outer function.

We can use it to expose private functions or data in a restricted way.

For example, we can write the following function that is a closure:

const foo = (() => {
  let x = 'Joe';
  const privateFn = () => {
    alert(`hello ${x}`);
  }

  return {
    publicFn() {
      privateFn();
    }
  }
})();

foo.publicFn();
Enter fullscreen mode Exit fullscreen mode

In the code above, we have an (Immediately Invoked Function Expression) IIFE that runs a function that returns an object with a publicFn property, which is set to a function that calls privateFn , which is hidden from the outside.

Also, privateFn is called with x declared inside the function.

Then we call publicFn after assigning the returned object to foo .

What the code achieves is that we hid the private items within a closure, while exposing what we want to expose to the outside.

As we can see, the closure lets us hold items that’s resides in a scope not available to the outside while we can expose what we can use outside the closure.

One major use of closures is to keep some entities private while exposing necessary functionality to the outside.

Conclusion

Hoisting is the pulling of functions and variables to the top of the code during compilation.

Function declarations are hoisted fully, and variables declared with var has everything before the value assignment hoisted.

The scope is where a piece of code has valid access to a variable or constant.

Closures are a way to return inner functions with some of the entities of the outer function included. It’s useful for keeping some things private while exposing some functionality.

Top comments (0)