作用域与作用域链

130 阅读3分钟

作用域是在运行时代码中的某些特定部分中的变量、函数和对象的可访问性。即作用域决定了代码区块中变量和其他资源的可见性。

function change(){
    var a = 'ellie'
}
change()  //要事先调用一下,不然读不到函数内部(js执行顺序)
console.log(a:', a)  //a is not undefined

作用域就是一个独立的地盘,让变量不会外泄、暴露出去。

最大的用处:隔离变量,不同作用域下同名变量不会出现冲突。 ES6之前javascript没有块级作用域,只有全局作用域和函数作用域。ES6新增了块级作用域,可通过let const实现.

全局作用域 和局部作用域

全局作用域

在代码中任何地方都能访问到的对象拥有全局作用域,这几种情况拥有全局作用域

  • 最外层函数、最外层函数外面定义的变量,拥有全局作用域
var a = 'ellie'                // 最外层变量
fuction change(){              // 最外层函数
    var b = 'jerry'            // 内层变量
    fuction innerChange(){     // 内层函数
        console.log('b:', b)
    }
}
  • 所有未定义直接复制的变量会自动声明,拥有全局作用域
function change(){
    a = 'ellie'
    var b = 'jerry'
}
change()
console.log(a)  //ellie
console.log(b)  // b is not undefined
  • 所有window对象的属性拥有全局作用域 一般情况下,window.alert,window.location等 全局作用域的弊端:如果多人协作,并且变量定义都没有用函数包裹,那这些变量都是在全局作用域中,如果两个人命名相同,就会出现命名冲突的问题。

函数作用域

函数作用域是指声明在函数内部的变量。只在固定的代码片段内可访问到

function change(){
    var a = 'ellie'
    function innerChange(){
	console.log('a:', a)
    }
}
console.log(a); // a is not undefined 阻塞掉后面掉执行,即使执行,也报错
innerChange()

内层作用域可以访问外层作用域,外层作用域不能调用内部作用域。

另:块语句(即:花括号中间的语句)不会创建一个新的作用域。

if(true){
    var a = 'ellie'
}
console.log(a)  // ellie

块级作用域

块级作用域可通过let const 声明,所声明的变量在指定的块的作用域外无法被访问,创建条件:

  • 一个函数内部
  • 一个代码块内部(花括号包裹内) 块级作用域的特点:
  • 声明不会被提升到当前代码块的顶部
  • 禁止重复声明
  • 循环中绑定块级作用域的妙用(for循环中)

作用域链

自由变量

自由变量:当前的作用域中没有定义的变量。

var a = 'ellie'
function change(){
    var b = 'jerry'
    console.log(a)  //这里a就是一个自由变量
    console.log(b)
}

自由变量如何得到值:要到创建函数的那个作用域中取,无论函数在哪里调用

var a = 'ellie'
function change(){
    console.log(a)
}
change()  // ellie
function show(){
    var a = 'jerry'
    change() // 全局作用域下创建的,所以打印的a还是全局下的a。跟在哪里调用的无关
}
show() // ellie