作用域

JavaScript中的作用域分为全局作用域函数作用域块作用域

全局作用域

对于全局范畴内申明的变量,能够在任何中央拜访。

var messge = 'Hello'function say(){  console.log(message)}say(); // Hello

函数作用域

在函数内申明的变量,只能从该函数外部拜访。

function say() {  var messge = 'Hello';  console.log(messge);}say(); // Helloconsole.log(greeting); // ReferenceError: messge is not defined

块作用域

ES6 引入了letconst 关键字,它们申明的变量只能从该代码块内拜访。

{  let messge = 'Hello';  console.log(messge);}console.log(messge); // ReferenceError: messge is not defined

动态作用域

在词法剖析时(编译时)确定。

let number = 42;function printNumber() {  console.log(number);}function log() {  let number = 54;  printNumber();}log(); // 42

作用域链

JavaScript运行时,引擎首先会在以后范畴内查找变量,如果找不到,会向父作用域查一层一层向上查找,始终找到顶层全局作用域,如果还是找不到就返回undefined

var g = 'Global hello'function f1() {    var g1 = 'G1 hello';    function f2() {        var g2 = 'G2 hello'        function f3() {            console.log(g, g1, g2)        }          f3()    }      f2();}f1(); // Global hello G1 hello G2 hello

运行剖析

执行上下文

执行上下文是执行一段 JavaScript 的环境,它存储了执行代码的一些必要信息。执行上下文分全局执行上下文函数执行上下文

  • 全局执行上下文,一个程序中只会有一个,函数之外的代码都在全局执行上下文中运行。
  • 函数执行上下文,函数在每次调用时都会创立一个对应的函数执行上下文

执行上下文的蕴含变量环境Variable environment),作用域链Scope chain),this 指向。

  • 变量环境,函数外部所有的变量和对象援用和调用参数。
  • 作用域链,以后函数之外的变量的援用组成。
  • this 指向。

从JavaScript运行时的内存构造来看,调用栈就是存储执行上下文的汇合。

案例

案例一

这是一个一般的JavaScript例子,运行流程剖析:

var msg = 'Global hello'function say() {    var msg = 'Hello'      return msg;}var s = say();console.log(message) // Hello
  1. 创立全局执行上下文,而后入调用栈。
  2. 调用函数say(),创立say()函数执行上下文,并入调用栈。
  3. 执行完say()函数将后果返回,更新全局执行上下文里的s 变量。
  4. say 函数的执行上下文弹出栈。

案例二

这个例子跟下面不同的是返回值是函数,这个匿名函数也称闭包,它拜访了函数内部的变量,即便内部函数执行上下文被弹出栈后,它仍然能够持有内部变量的援用。运行剖析如下:

var msg = 'Global hello'function say() {    var msg = 'Hello'    return function() {        console.log(msg)    };}var s = say();s()
  1. 创立全局执行上下文,而后入调用栈。
  2. 调用函数say(),创立say()函数执行上下文,并入调用栈。
  3. 执行完say()函数将后果返回,更新全局执行上下文里的s 变量,s 是函数类型,它仍然持有say var = msg 援用。
  4. say 函数的执行上下文弹出栈。
  5. 执行 s() ,创立s()函数执行上下文
  6. s() 函数的执行上下文弹出栈。

思考题

在脑海里动静执行上面代码。

题目一:

var msg = 'Global hello'function getMsgFunc() {    var msg = 'Hello';    function getMsg() {        return msg;    }    return getMsg();}console.log(getMsgFunc());

题目二:

var msg = 'Global hello'function getMsgFunc() {    var msg = 'Hello';    function getMsg() {        return msg;    }    return getMsg;}console.log(getMsgFunc()());

题目三:

     var msg = 'Global hello'  var obj = {    msg : 'Hello',    getMsgFunc : function(){      return function(){        return this.msg;      };    }  };  console.log(obj.getMsgFunc()());

题目四:

     var msg = 'Global hello'  var obj = {    msg : 'Hello',    getMsgFunc : function(){              var that = this      return function(){        return that.msg;      };    }  };  console.log(obj.getMsgFunc()());