作者:小啊小二饼(iconfont)

🌑

Spaghetti.ink

Appreciation, Modesty, Persistence


Js - Hoisting & Scope

Hoisting

Function Hoisting:

Invoke a function that is declared behind.

myFunc(); // => Show up!

// Using Function Declaration
function myFunc() {
  console.log("Show up!")
}

:warning:Using function expression will not hoist.

myFunc2(); // => myFunc2 not a function

// Using Function Expression
var myFun2 = function myFunc2() {
  console.log("Show up!")
}

Declaration Hoisting:

When a variable is declared withvar, the declaration is lifted up (or “hoisted”) to the top of the enclosing function.

/* Hoisting with var */
console.log(a) // => undefined
var a = 2;

/*
 * 1. var a;
 * 2. console.log(a);
 * 3. a = 2;
 */

:warning: How about let ?

/* Hoisting with let */
console.log(a) // => ReferenceError, access before initialization
let a = 2

While variables declared with var keyword are hoisted (initialized with undefined before the code is run) which means they are accessible in their enclosing scope even before they are declared.

let variables are not initialized until their definition is evaluated (assigned). Accessing them before the initialization results in a ReferenceError. The variable is said to be in “temporal dead zone (TDZ)” from the start of the block until the initialization is processed.

Scope

  • What’s Scope?

    Any variables, functions defined in a scope can only in effect within that scope.

    e.g. Defined two function in two js files with the same name, they won’t influence each other.

  • Type [From Def of Js (p125)]

    • Block Scope

      The scope of a variable is the region of your program source code in which it is defined. Variables and constants declared with let and const are block scoped, which means only defined within the block of code in which the let or const statement appears.

      Roughly speaking, if a variable or constant is declared within a set of curly braces, then those curly braces delimit the region of code in which the variable or constant is defined.

      Variables and constants declared as part of a for, for/in, or for/of loop have the loop body as their scope, even though they technically appear outside of the curly braces.

    • Global Scope

      Defined outside the block. for node.js and client-side Javascript modules, the scope is the file that the variable is defined in; for client-side Javascript, the scope is the HTML file.

Closure

A function defined inside another function is called a nested function. Nested functions can access variables of the enclosing scope.

Unlike a plain function, a closure allows the function to access those captured variables through the closure’s copies of their values or references, even when the function is invoked outside their scope.

Like most modern programming languages, JavaScript uses lexical scoping. This means that functions are executed using the variable scope that was in effect when they were defined, not the variable scope that is in effect when they are invoked.

Technically, all JavaScript functions are closures:

function outter(outArg) {
  	let a = 1; 
    return function inner(innerArg) {
        return outArg + innerArg;
    }
}

let innerFunc = outter(1)
console.log(innerFunc(2))
Interesting Example
let funcList = [];

for (var i = 0; i < 5; i++) {
    function out() {
        return i;
    }
    funcList.push(out);
}

for(func of funcList) {
    console.log(func())
}

/*
	Output:
	=> 5
	=> 5
	=> 5
	=> 5
	=> 5
	
	Can you explain the result by scope?
*/

What if using let in loop?

let funcList = [];

for (let i = 0; i < 5; i++) {
    function out() {
        return i;
    }
    funcList.push(out);
}

for(func of funcList) {
    console.log(func())
}

/*
	Output:
	=> 0
	=> 1
	=> 2
	=> 3
	=> 4
*/

Actually, in loops, you get a fresh binding for each iteration if you let-declare a variable. The loops that allow you to do so are: for, for-in and for-of. And the following codes are the codes converted by Babel from ES6 to ES5 (in which let is not introduced yet)

"use strict";

var funcList = [];

var _loop = function _loop(i) {
  function out() {
    return i;
  }

  funcList.push(out);
};

for (var i = 0; i < 5; i++) {
  _loop(i);
}

for (var _i = 0, _funcList = funcList; _i < _funcList.length; _i++) {
  func = _funcList[_i];
  console.log(func());
}
Excerise

What’s the result of following code, explain it by scope.

let funcList = [];
for (let i = 0; i < 5; i += 2) {
    function out() {
        return i;
    }
    funcList.push(out);
    --i;
}

for (func in funcList) {
    console.log(func())
}

/*
	Output:
	=> -1
	=> 0
	=> 1
	=> 2
	=> 3
	
	Explain:
	Cause while using let, in loops, you get a fresh scope each iteration.
*/

References

本文由 Frank采用 署名 4.0 国际 (CC BY 4.0)许可

— 2021年12月3日

本文总阅读量

JavaScript

本站总访问量