什么是作用域
作用域是指程序源代码中定义变量的区域。它规定了程序执行时对该变量的访问权限。
js中的作用域有什么特点
前面我们聊了什么是作用域,那javascript中作用域都有哪些特点呢?接下来我们就聊聊这个
动态作用域和静态作用域
在讨论这个问题之前先看一段如下代码:
var a = 1
function f1 () {
console.log(a)
}
function f2 () {
var a = 2
f1()
}
f2()
上述代码会打印1。这就很好的说明了,在javascript中,其作用域是静态作用域也就是词法作用域。通俗点来讲,函数的作用域在定义的时候就已经定了。套用作用域的概念就是函数f1在定义的时候,就规定了访问的变量a是全局变量中的a,因此当在函数f2中执行的时候,函数f1没有访问函数f2中的局部变量a的权限。
全局作用域、局部作用域及块作用域
- 全局作用域:变量在全局声明就拥有了全局作用域
- 局部作用域:在函数内声明的变量,至于在函数体内有定义,他们是局部变量,作用域是局部性的,因此其权限就是局部作用域。特别注意:函数参数也是局部变量
- 块级作用域:在一些类c语言中,花括号内的每一段代码都具有各自的作用域,变量在声明他们的代码块外是不可见的,我们称之为块级作用域。在ECMAScript6之前,javascript中是没有块级作用域的概念的。
这几个作用域从优先级上来说,块级作用域 > 函数作用域 > 全局作用域 我们来看下面一段代码:
var scope = 'global'
function checkscope () {
var scope = 'local'
let i = 10
{
let i = 8
console.log(i) // => 8
}
return scope
}
checkscope() // => 'local'
变量提升
在如下代码中我们定义了变量a,b,c,他们都在同一个作用域内。
function test (d) {
console.log(a) // => undefined
console.log(b) // => undefined
console.log(c) // => undefined
var a = 1
if (d > 0) {
var b = 2
for (var c = 0; c < 10; c ++) {
console.log(c) // =>0 - 9
}
console.log(c) // =>10
}
console.log(b) // =>2
}
test(1)
我们发现javascript函数作用域在整个函数体内始终可见,即便是在判断语句和循环语句中也没有收到影响。这意味着变量在声明前就已经可用。javascript的这个特性就称为声明提前也叫变量提升。
作用域链
到底全局作用域跟局部作用域什么关系呢?还有大家可能会疑惑,我们再聊javascript静态作用域的时候函数f1是怎样访问到全局变量a的呢?
- 作用域链 每一段javascript代码(全局或者函数)都有一个与之关联的作用域链,这个作用域链是一个对象列表或者链表,这组对象定义了这段代码"作用域中"的变量。当javascript需要查找变量a的时候,他会沿着这条链查找第一个对象看它有没有a变量,如果没有就查找第二个对象,如果还没有就接着查找下一个,一次类推,直到找到,若作用域链上没有一个对象含有a属性,那么就认为这段作用域链上不存在该属性,最终或抛出一个引用异常错误。
- 在javascript的最顶层代码中(不包含任何函数定义的代码),作用域链由一个全局对象组成。在不包含嵌套的函数体中,作用域链上有两个对象,第一个是定义函数参数和函数对象的对象,第二个就是全局对象。
今天我们聊了一聊javascript中的作用域,可能大家已经发现啦我说了半天作用域好像跟javascript运行时没有什么关系啊,别着急,后续还会在接着聊。