JS Scope / Hoisting

JS Scope / Hoisting

笔记性质
建议搭配服用 : JS 执行环境
菜鸟初学,为了避免误人子弟,请大神留步勘误 QQ

範例

先来个範例,猜猜结果为何?

  var foo = 1;  function bar() {    console.log('bar First',foo)    if (!foo) { var foo = 10; }    console.log('bar Last',foo);  }  bar();
bar First: undefinedbar Last:  10

题目解析

执行 bar() 建立执行环境创建阶段: 将 var foo 提升至最上,但不会给予值 (此时为undefined)执行阶段: log('first', foo) 得到 undefinedfoo 为 undefined (falsy) !fasle得到 true因此可执行 if 内容 给予 foo 值log('last',foo) 得到10不熟falsy可见此
  var foo = 1;  function bar() {      var foo;       // 这里改了      console.log('bar First',foo) // undefined      if (!foo) {          foo = 10;  // 这里改了      }      console.log('bar Last',foo); // 10  }  bar();

Scope

ES5 为 函数级作用域(function-level scope)

ES5 (var) Scope 切割单位为 Function

因此 ES5 需要用 IIFE 来产生区域的 scope

ES6 以 {} 做划分,使用 let / const 即可 (Blocak-level scope)

Scope Chain 範围链
找寻变量的过程,由内往外找,直到全域环境。

注意 若在 Function 内 没有用 var 重新宣告,会产生全域变数
,进而变成改写全域变数中的 myVar

Outer Environment 外部环境
当该执行环境找不到该变量时,会往外部环境做参照

要如何区分 Outer Environment (外部环境) : 看程式码的相对位置

var myVar = 'Global'function a() {  var myVar = 'Local'  function b() {    // b 的外层为 a()    console.log(myVar) // Local  }  return b}// c 的外层为 Globalfunction c() {   console.log(myVar) // Global}a()()c()
小测试
  var x  = 1  if (true) {    var x = 2    let y = 2    console.log(x)  // ? a    console.log(y)  // ? b  }  console.log(x)  // ? c  console.log(y)  // ? d

Ans
a : 2 / b : 2 / c : 2 / d : y is not defined

ES5 var Scope 切割单位为 Function
因此 if else 中的 var x = 2 等同于 重新宣告了 x

Hoisting 观念

使用 var 时,不论是否被执行,变数宣告皆会被提升至环境的最上方
执行环境的建立阶段,就已经将变数宣告加入该环境当中了,
即 执行环境的建立阶段,已进行Hoisting了

函式的 Hoisting

函式 宣告式 会整块程式码被 Hoisting,因此可于宣告前使用函式 表达式 则只有变数宣告的部分被 Hoisting,
因此于宣告前呼叫,会回传 undefined,执行到该行时,才会进行给予值
foo() // foo is not a functionbaz() // baz is not a functionbar() // 可用,函式宣告式,整块被提升function bar() = {}var foo = function () {}; // 匿名函式表达式 (只有foo被提升)var baz = function spam() { // 命名函式表达式 (只有baz被提升)    // spam 变数名称 只可以用于此区块    console.log(spam) // 指向此 Function}; // Scope Chain 只可往外找,无法往内找spam(); // ReferenceError "spam is not defined"// IIFE 同 命名函式表达式 概念;(function bzz() {  var inSide = 123  console.log(bzz) // 指向此 Function}())// IIFE 为 Function , Scope Chain 只可往外找,无法往内找console.log(inSide) // inSide is not definedconsole.log(bzz) // bzz is not defined

练习题

function b() {    console.log(myVar) // a    var myVar    console.log(myVar) // b}function a() {    var myVar = 2    b()    console.log(myVar) // c    function d() {      console.log(myVar) // d    }    d()}var myVar = 1console.log(myVar) // ea()

Ans
a : undefined / b : undefined / c : 2 / d : 2 / e : 1

a 因为 myVar 会在 b 中 hoisting 因此不会取到外部变数,
而是取到 var myVar; 的 undefined 值

总结 重要重点

ES5 Scope 切割单位为 Function

ES6 let const 为 Block Scope 因此只需要以 {} 划分

使用 var 时,不论是否被执行,变数宣告皆会被提升至环境的最上方

Hoisting 于 建立 执行环境 的 建立阶段 执行 (複习 JS 执行环境)

只会 Hoisting 宣告的部分,赋値仍要在执行阶段执行。

函式宣告式 : 会 Hoisting 整块程式码,因此可于宣告前使用

函式表达式 : 只会提升宣告的部分,赋値仍要在执行阶段执行。

参考资料

andyyou
DavidShariff
PJChENder
ben cherry


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章