作用域表示当前执行的上下文,值与表达式在其中可见,可以被访问到的上下文,作用域决定了区块代码中的可见性。
js,作用域可分为全局作用域,局部作用域,块级作用,在javascript中一般有三中情况拥有全局作用域,
作用域存在的意义:变量隔离,不同作用域下的同名变量不会出现冲突
** 一、全局作用域**
1.window对象到的属性、方法
console.log(window.alert);
如图,所有的window对象的属性都拥有去全局作用域,之所以javascript中的任何地方都能alert(‘xxxx’),是因为它被定义在了window对象上的一个函数,拥有全局作用域
** 2.定义在最外层的变量、函数、对象**
c=3 //外层变量
//最外层函数
function fun1(){
//内层变量
a=1;
a=2;
//内层函数
function fun2(){
b=2;
}
}
console.log(c); //3
console.log(a); // not definded
console.log(fun1) //function fun1()
console.log(fun2) //fun2 is not defined
变量a与函数fun1拥有全局作用域,在任何地方都可以访问,可,变量b与fun2没有定义在全局作用域里,在全局作用域中无法访问
3.所有未定义直接赋值的变量自动声明为拥有去全局作用域
function fun(){
a=2;
var b=2;
}
fun()//首先的执行一下这个函数不然不知道里面是啥
console.log(a) // 2
console.log(b) // b is not defined
b var定义并且赋值了,而变量a只是在函数中直接赋值并没有定义 ,那么变量a,会自动挂到window对象上,拥有全局作用域。
ps: 常量和变量都属于变量,只不过常量是赋过值不能再改的变量,而普通的变量可以进行赋值操作(有人可能会疑问a,明明是常量,(^o^)/~)
**二、局部作用域 **
局部作用域相当于函数作用域,指函数内部的空间,函数内部的变量,外部无法访问
function doSomething(){
var blogName="xx";
function innerSay(){
alert(blogName);
}
innerSay();
}
alert(blogName); //脚本错误
innerSay(); //脚本错
作用域是分层的,内层作用域可以访问外层作用域的变量,反之不行。
三、块级作用域
ES5只有全局作用域没和函数作用域,没有块级作用域,这带来很多不合理的场景。
第一种场景,内层变量可能覆盖外层变量:
var tmp = new Date();
function f(){
console.log(tmp);
if(false){
var tmp = "hello";
}
}
f(); // undefined
上面代码中,函数f执行后,输出结果为undefined,原因在于变量提升,导致内层的tmp变量覆盖了外层的tmp变量。
第二种场景,用来技术的循环变量泄露为全局变量:
var s = "hello";
for(var i=0;i<s.length;i++){
console.log(s[i]);
}
console.log(i); // 5
上面代码中,变量i只用来控制循环,但是循环结束后,它并没有消失,泄露成了全局变量。
实际上正是es6,let的出现让javascript拥有了块级作用域
**var ** 无块级作用域
function fun(){
var n =10
if(1==true){
var n=5
}
console.log(n) //5
}
fun();
let 有块级作用域
//块级作用域
function fun(){
let n =10
if(1==true){
let n=5
}
console.log(n) //10
}
fun();
var 同一个作用域下可以重复声明
function fun(){
var n =10
if(1==true){
var n=5
var n=9//var允许重复声明
}
console.log(n) //9
}
fun();
let 同一个作用域下不能重复声明
//块级作用域
function fun(){
let n =10
if(1==true){
let n=5 //let不允许重复声明
let n=9
}
console.log(n) // 脚本报错
}
fun();
** 作用域链**
当在某个函数内部作用域中查找某个变量时,如果没有就找到他的父级作用域中去查找,若是父级作用域也没有,就会一层一层往上找,直到找到全局作用域还没找到的话,就结束寻找,认定变量未定义.这种一层一层的作用域嵌套关系,就是作用域链。
案例:
let a =1;
function func1(){
let b=2;
function func2(){
let c=3;
console.log(a); //输出全局变量a=1,根据作用域链查找
}
func2();
}
func1();
附一个面试题:
在以下代码中: typeof a 和typeof b的值 分别是什么?
看代码:
function foo(){
let a=b=0;
a++;
// return a;
console.log(a)
}
foo();
console.log( typeof a) undefined
console.log( typeof b) number
//a???? b???
我们仔细看看第2行:let a = b = 0。这个语句确实声明了一个局部变量a。但是,它确实声明了一个全局变量b。
在foo()作用域或全局作用域中都没有声明变量 b 直接赋值了”。因此JavaScript将表达式 b = 0 解释为 window.b = 0。
b是一个偶然创建的全局变量。
在浏览器中,上述代码片段相当于:
function foo() {
let a; window.b = 0; a = window.b; a++;
return a;
}foo();
typeof a; // => 'undefined'
typeof window.b; // => 'number'
typeof a是 'undefined'。变量a仅在 foo()范围内声明,在外部范围内不可用。typeof b等于'number'。b是一个值为 0的全局变量。
版权归原作者 编码~ 所有, 如有侵权,请联系我们删除。