变量是任何语言中都不可获取的一个东西。无论你使用的是何种语言,毫无疑问的是一定会使用到非常多的变量。这时就存在有一个问题,一个变量可以在页面中的作用范围到底有多大?我创建的变量是否可以在任意的位置访问到?变量的作用范围,也就是变量的作用域,变量的作用域决定了它可以在哪些位置被访问到。
全局作用域
全局作用域是整个JS中最大的作用域,所有的直接写在script标签中的代码都位于全局作用域中(不在任何的其他代码块中)。在全局作用域中创建的变量叫做全局变量,在全局作用域中创建的函数属于全局函数。全局变量和函数可以在任意的位置被访问到。
let a = 10
// 全局变量
let b = 'hello'
// 全局变量
function
fn
() {
// 全局函数 // 略...
} (function () { console.log(a, b)
fn
() })() console.log(a, b)
上例中,变量a和变量b以及fn函数都直接写在了全局作用域中,所以a、b和fn都属于全局变量(函数)。这种全局变量可以在全局作用域中访问也可以在其他作用域中访问到。
局部作用域
在全局作用域内部的小作用域统统称为局部作用域,局部作用域中创建的变量和函数被称为局部变量(函数),只能在内部访问到,外部无法访问。局部作用域有两种:一种叫做块作用域,一种叫做函数作用域。
块作用域
每一个代码块({})都是一个块作用域,块作用域是一种局部作用域。块作用域的代码只能在块内部访问,无法在外部访问。
{
// 代码块1
let a = 10
// 局部变量
let b = 'hello'
// 局部变量
{
// 代码块2
console.log(a, b)
// 可以在块内部访问
} }
// 无法在全局作用域中访问到局部变量
console.log(a, b)
// 报错 Uncaught ReferenceError: a is not defined
上例中,变量a和b声明在了{}内部,我们称为代码块1。在代码块1中代码就在一个块作用域中,所以a和b是两个局部变量,这两个局部变量只能在代码块1中被访问。另外代码块2属于代码块1内部的代码块,所以在代码块2内部可以访问到代码块1中定义的变量,但是反过来,如果在代码块2中定义了变量,无法在代码块1中访问。最后一行,我们尝试在全局作用域中访问变量a和b,浏览器会报错,因为在全局作用域中看不到局部变量。
编写代码时,if语句、switch语句的代码块,for语句、while语句的循环体都属于块作用域。
另外需要注意,如果你使用var关键字声明变量是没有块作用域这一说的。
{
var a = 10// var声明的变量没有块作用域
var b = 'hello'
// var声明的变量没有块作用域
}
console.log(a, b)// var声明的变量没有块作用域 可以访问
上例代码中,变量a和b都使用var关键字来声明,没有块级作用域一说,所以它属于全局变量,可以在任意位置访问。
函数作用域
函数作用域也属于一种局部作用域,所有的在函数内部编写的代码都在函数作用域中。和块作用域类似,函数作用域中的变量和函数只能在内部访问,在函数外部无法访问。
function
fn
() { let a = 10 let b = 20 console.log(a, b)
// 局部变量,在函数内部可以访问
}
fn() // 调用fn函数,使代码执行
// 局部变量,无法在全局作用域中访问
console.log(a, b)
// 报错 Uncaught ReferenceError: a is not defined
在函数作用域中,使用var关键字声明的变量的也是局部变量,只能在函数内部访问,但是如果声明变量是没有使用任何的关键字,则此时变量将会自动变成全局变量。
function
fn
() { a = 10
// 不使用关键字声明,变量成为全局变量
b = 20 console.log(a, b) }
fn
()
// 调用fn函数,使代码执行
console.log(a, b)
// 全局变量可以访问
最佳实践
1.尽量不要直接在全局作用域中编写变量和函数
全局作用域可以在任意位置访问到,如果直接在全局作用与中创建变量和函数,它们可以在任意的位置被访问到,但与此同时也会带来一个问题,变量和函数有可能被意外的修改或覆盖。尤其是多人开发时问题会更加明显。
所以我们创建变量时需要将变量创建到一个局部作用域中,而不要创建在全局作用域。主要处理方式有两种,第一种,将变量定义在一个立即执行函数内部:
(function () { let a = 10 let b = 20
// 略...
})()
在匿名函数内部的代码都属于局部作用域(函数作用域)。不会对全局作用域产生影响。
第二种,将变量和函数存储到一个对象中。
const myTools = {
a:10,
b:'abc',
fn:function () {
//略...
}
}
将变量存储为一个对象的属性,将函数存储为对象的方法,同样也不会对全局作用域产生影响,但是这种方式依然会创建出一个全局变量(存储变量的对象),所以多人开发时一定要分配好对象名,千万不要出现重名。
2. 使用变量时一定要声明
变量的声明有三个关键字let、const和var。使用变量时一定要对其进行声明,尤其是在函数作用域中,不声明直接使用会导致变量变成全局变量,切记。
3. 使用let和const,不要使用var
由于var并没有块作用域,在开发时会给我们带来一些不便。所以编写代码时不要使用var关键字而要使用let和const。那么什么时候使用let,什么时候使用const呢?一般情况下,基本数据类型使用let,对象和函数可以使用const。但是实际情况会更加复杂一些,如果暂时不会区分,可以全都使用let。