Scope 作用域
Scope 是指在 JavaScript 程式中,一个变数可用 (或有效) 的範围,而在这个有效範围之外,变数是无法被使用的。举个常见的例子,我们在 Function 中定义的变数,无法在函式外取得,这也是为什么我们需要使用 return
回传的方式将计算出来的结果返回到函式呼叫处的原因。
在 JavaScript 中,Scope 主要又分为两大类 - Global Scope (全域) 及 Local Scope (区域)。
Global Scope 全域
在 Global Scope (全域) 中「宣告」的变数,也就是指在 JavaScript 档案最外层 (所有 Function
和区块之外) 被宣告的变数,被称为全域变数 (Global Variables)。全域变数可以从网页的任何地方,包括每个 Function
、区块中进行赋值、取值等操作。
如下範例,程式最外层中分别有两种方法定义的全域变数 a
和 b
,不管在单纯的 if 区块
或 function 函式
内都可以取得该变数。
let a = 1;var b = 2;if (true) { console.log(a); // 1 console.log(b); // 2}function add() { console.log(a); // 1 console.log(b); // 2};add(); // 呼叫 add()
Local Scope 区域
Local Scope (区域) 则和全域变数相反,是指在 Fucntion 函式
或 Block 区块
内所宣告的变数,这类变数无法在宣告区域之外使用,所以被称为区域变数。
而区域变数又因最早的 var
及后来在 ES6 新增的 let
两种宣告方式有效範围的差别分为 Function Scope 函式作用域
和 Block Scope 区块作用域
。
Function Scope 函式作用域
函式作用域是指在在函式中宣告的变数只能在函式区块内作用,是基于 var
以函式作为区块分隔的特性而来。也就是说在使用 var
时,所有不在 Function
内宣告的变数都是全域的。
有点複杂,以下用几个範例来说明:
function add() { var x = 2; console.log(x); // 2};add();console.log(x); // 报错,无法取得 x
所有在函式外(包括 if 区块内)宣告的变数对 var 来说都是全域的var a = 1;if (true) { // if 不是 function var b = 2; // 对 var 来说 b 也是全域变数,在任何地方都能使用}console.log(a); // 1console.log(b); // 2
判断是区域或全域变数的基準是变数「宣告」的位置,而非首次赋值的位置var a; // 在最外层宣告function add () { a = 2 // 在函式中赋值}add();console.log(a); // 2
只要没有在 Function 内进行宣告的都是全域变数 (包含没有宣告直接在函式内使用的变数)// a 未宣告function add() { a = 3; // 只在 function 中赋值,没有进行宣告,不算区域变数 // 未宣告直接使用,不符合规範但 var 不会报错};add();
Block Scope 区块作用域
Block Scope 区块
出现是基于 ES6 中新宣告方式 let
之作用域与 var
不同而来的概念,使用 let
宣告时,在区块 ({}
)中宣告的变数只会在 {}
中有效,也就是说若在 if{}
条件区块内使用 let
声明变数,则该变数为区域变数。
{}
包裹,不管是条件区块或任何区块,let
宣告的变数都是区域变数if (true) { let a;}console.log(a); // not defined// 单纯用区块符号包裹也是区域变数{ let b;}console.log(b); // not defined
全域区域变数名称相同
当全域变数和区域名称相同时,例如已有一全域变数 a
后又在函式内宣告区域变数 a
,我们要怎么知道现在在操作哪个变数呢?
答案是「找最近的」!
让我们先来看看 var
的情境:
var x = 1; // 全域console.log(x); // 1function add() { console.log(x); // 1};add();console.log(x); // 1
有一全域变数 x 又在函式内宣告一次 x,则会将两个 x 视为不同的变数,找离自己最近的 (Function 内归 Function 内,全域归全域)var x = 1; // 全域console.log(x);function add() { var x = 5; // Function 内宣告同名变数,是区域变数 console.log(x); // 5 x = 10; // 会找最近的,所以在 Function 内操作的都是区域变数 console.log(x); // 10};add();console.log(x); // 1 区域变数不影响全域变数
函式内先使用变数再进行宣告,宣告前值为 undefined
,不会拿全域变数的值var x = 1; // 全域console.log(x);function add() { console.log(x); // undefined var x = 5; console.log(x); // 5};add();console.log(x);
接着来看看 let
:
let
的规则与 var
大致相同,若在全域和区域有相同名称的变数时,会找最近的let x = 1; // 全域console.log(x); // 1function add() { let x = 5; console.log(x); // 5};add();console.log(x); // 1
不同的是 let
无法先使用再宣告,所以下範例会报错let x = 1; // 全域console.log(x); // 1function add() { console.log(x); // 报错,区域内宣告同名变数,所以与全域的 x 为不同变数 let x = 5; console.log(x);};add();console.log(x);
结论
对于 let
和 var
这两种宣告方式,其实在全域和区域的概念大致相同,差别在于两者的「作用域」分别是 区块
及 函式
,只要分清楚两种方法的差异就可以很容易弄懂其中的逻辑啦!
上一篇:[快速入门前端 54] JavaScript:Function 函式 (2) 参数和回传
下一篇:[快速入门前端 56] JavaScript:Array 阵列 (3) 常见阵列操作方法
系列文章列表:[快速入门前端] 系列文章索引列表