ES5中的作用域
一、全局变量
全局变量有 全局作用域: 网页中所有脚本和函数均可使用
如果变量在函数内没有声明(没有使用 var 关键字),该变量为全局变量
1.最外层函数和在最外层函数外面定义的变量为全局变量,拥有全局作用域:
var boyName = "刘家军"
function person(){
var girlName = "袁姮"
function doSth(){
console.log(girlName)
}
doSth()
}
console.log(boyName) // 刘家军
console.log(girlName) // 报错: girlName is not defined
person() // 袁姮
doSth() // 报错:doSth is not defined
2.所有末定义直接赋值的变量为全局变量,拥有全局作用域:
function doSth(){
var boyName = "刘家军"
girlName = "袁姮"
console.log(boyName )
}
doSth() // 刘家军
console.log(girlName) // 袁姮
console.log(boyName) // 报错:boyName is not defined
3.所有window对象的属性拥有全局作用域
二、局部变量
变量在函数内声明,变量为局部变量,拥有局部作用域,因为只能在函数内部访问,也称作函数作用域
function person(){
var boyName = "刘家军"
function doSth(){
console.log(boyName)
}
doSth()
}
console.log(boyName) // 报错:boyName is not defined
doSth() // 报错:doSth is not defined
三、变量提升
在ES6之前,JS没有块级作用域,只有全局作用域和函数作用域。变量提升即将变量声明提升到它所在作用域的最开始的部分。看代码:
console.log(boyName) // undefined
var boyName = "刘家军"
console.log(boyName) // 刘家军
function person() {
console.log(girlName) // undefined
var girlName = "袁姮"
console.log(girlName ) // 袁姮
}
person();
之所以会是以上的打印结果,是由于js的变量提升,实际上上面的代码是按照以下来执行的:
var boyName // 变量提升,全局作用域范围内,此时只是声明,并没有赋值
console.log(boyName) // undefined
boyName = "刘家军" // 此时才赋值
console.log(boyName) // 打印出刘家军
function person () {
var girlName // 变量提升,函数作用域范围内
console.log(girlName)
girlName = "袁姮"
console.log(girlName )
}
person()
ES6中的块级作用域
‘块级作用域’(一对花括号{}即为一个块级作用域)通过新增命令let和const来体现,
let
let和var差不多,都是用来声明变量的。区别就在于:
1、 let声明的变量只在所处于的块级有效
2、 let没有‘变量提升’的特性,而是‘暂时性死区’特性
1.let声明的变量只在块级有效
function person(){
if(true){
let boyName = "刘家军"
console.log('in:' + boyName ) // 刘家军
}
console.log('out: ' + boyName ) // 报错:boyName is not defined
}
在if外打印boyName ,报错:boyName is not defined
这因为let声明的变量boyName 是属于if内的块级作用域;而不是像var一样
2.let没有‘变量提升’的特性,而却有‘暂时性死区’的特性
var boyName = "刘家军"
function person(){
console.log(boyName) // 报错:boyName is not defined
let boyName = "刘家军测试";
};
person()
boyName报错了,说明变量提升了,只是let规定了不能在其声明之前使用而已。我们称这特性叫“暂时性死区”。这一特性,仅对遵循‘块级作用域’的命令有效(let、const)
3.可以解决闭包问题
var arr = [];
for(var i = 0; i < 2; i++){
arr[i] = function(){
console.log(i);
}
}
arr[1]() // 2
var arr = [];
for(let i = 0; i < 2; i++){
arr[i] = function(){
console.log(i);
};
};
arr[1]() // 1
关于闭包 我们明天再仔细讲一讲
const
const命令与let命令一样,声明的变量,其作用域都是块级。
所以const遵循的规则与let相差无二,只是,const是用来声明恒定变量的。
且,用const声明恒定变量,声明的同时就必须赋值,否则会报错。
function test(){
const num//报错,声明就得赋值
num = 666
console.log(num)
}
作用域链的组成
在JS中,函数的可以允许嵌套的。即,在一个函数的内部声明另一个函数
function person(){
var boyName = "刘家军";
function getName(){ // 在person函数内部,声明了函数getName,这就是所谓的函数嵌套。
var girlName = "袁姮";
}
}
对于person来说,person函数在执行的时候,会创建其person函数的作用域, 那么函数getName在创建的时候,会引用person的作用域,如图:
函数getName在执行的时候,其作用域类似于下面:
从上面的两幅图中可以看出,函数getName在执行的时候,是会引用函数person的作用域的。所以,像这种函数作用域的嵌套就组成了所谓的函数作用域链。当在自身作用域内找不到该变量的时候,会沿着作用域链逐步向上查找,若在全局作用域内部仍找不到该变量,则会抛出异常。
友情链接: 点击查看所有文章目录