js - 12 JS作用域和作用域链
2019-11-06 本文已影响0人
大怪兽迪迦
作用域
-
在一些类似C语言的编程语言中,花括号内的每一段代码都具有各自的作用域,而且变量在声明它们的代码段之外是不可见的,我们称为块级作用域。
-
而在js中并没有块级作用域,取而代之的使用了函数作用域:变量在声明它们的函数体以及函数体嵌套的任意函数体都是定义的
-
如下:
function test(o){
var i = 0; // i在整个函数体内均是有定义的
if(typeOf o == "object"){
var j = 0; // j在函数体内是有定义的,不仅仅在这个代码段
for(var k = 0; k < 10; k ++){ // k在函数体内是有定义的,不仅仅在这个循环内
console.log(k) // => 1~9
};
consloe.log(k) // => k已经定义,输出10
};
console.log(j) // => j已定义,但没有初始化
}
- js的函数作用域是指在函数内声明的所有变量在函数体内始终是可见的有意思的是,这就意味着变量在申明之前就甚至已经可用(这种特性被非正式的成为“声明提前”,即javascript引擎的“预编译”时进行)
如:
var scope = "global";
function f(){
console.log(scope); // 输出undefined,而不是“global”
var scope = "local"; // 变量在这里赋值,在函数体内的任何位置都有定义
console.log(scope); // 输出“local”
}
以上,虽然在函数f()外,scope被定义,但执行到函数内第一行时就被重新定义,但未被赋值,所以输出undefined,运行到第二行时才被赋值。为了方便理解上述函数f()可以写成
function f(){
var scope;
console.log(scope);
var scope = "local";
console.log(scope);
}
作用域链(纯理论,理解!理解!理解!)
- javascript是基于词法作用域的语言,即通过阅读包含变量定义在内的源码就能知道变量的作用域
- 全局变量在程序中始终有定义,局部变量在声明它的函数体内以及所嵌套的函数内有定义
概念
每一段js代码都有一个与之关联的作用域链,这个作用域链是一个对象列表或者链表,这组对象定义了这段代码“作用域中”的变量,当js需要找一个变量x时,会从链中的第一个对象开始,没有就找下一个,如果在一个对象中找到名为x的属性,就会停止,如果在链中没有找到说明该链中并不存在x,并最终抛出一个引用错误(ReferenceError)异常.
- 在js最顶层的代码中(也就是不包含在任何函数定义内的代码),作用域由一个全局对象组成。
- 在不包含嵌套的函数体内,作用域链上有两个对象:
1.定义函数参数和局部变量的对象。
2.全局对象 - 在一个含有嵌套函数体内,作用域链上至少有三个对象
理解
- 当定义一个函数时,它实际上保存一个作用链。调用这个函数时,将创建一个新的对象来储存它的局部变量,并将这个对象添加至保存的那个作用链上,同时创建一个新的更长的表示函数调用作用域的”链“
- 对于嵌套函数来讲,每次调用一个外部函数时,作用域都是不同的,内部函数又会重新定义一遍。因为每次调用外部函数的时候,作用域链型都是不同的,内部函数在每次调用的时候都有微妙的差别(在每次调用外部函数时,内部函数的代码都是相同的,而且关联这段代码的作用域链也不同)。