作用域
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 引入了let
和const
关键字,它们申明的变量只能从该代码块内拜访。
{ 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
- 创立全局执行上下文,而后入调用栈。
- 调用函数
say()
,创立say()
的函数执行上下文,并入调用栈。 - 执行完
say()
函数将后果返回,更新全局执行上下文里的s
变量。 - 将
say
函数的执行上下文弹出栈。
案例二
这个例子跟下面不同的是返回值是函数,这个匿名函数也称闭包,它拜访了函数内部的变量,即便内部函数执行上下文被弹出栈后,它仍然能够持有内部变量的援用。运行剖析如下:
var msg = 'Global hello'function say() { var msg = 'Hello' return function() { console.log(msg) };}var s = say();s()
- 创立全局执行上下文,而后入调用栈。
- 调用函数
say()
,创立say()
的函数执行上下文,并入调用栈。 - 执行完
say()
函数将后果返回,更新全局执行上下文里的s
变量,s
是函数类型,它仍然持有say
var = msg
援用。 - 将
say
函数的执行上下文弹出栈。 - 执行
s()
,创立s()
的函数执行上下文。 - 将
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()());