作用域表示当前执行上下文,值和表达式在该上下文中可见并且可以访问。 范围决定了块代码中的可见性。
Node.js的作用域可以分为全局作用域、局部作用域和块级作用域。 在javascript中,通常存在全局范围的中学情况。
1. 全球范围
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:常量和变量都是变量javascript 变量 作用域,但是常量是赋值后就不能改变的变量javascript 变量 作用域,而普通变量可以对形参进行操作(有人可能会奇怪a,明明是常量,(^哦^)/~)
2. 本地范围
局部作用域相当于函数作用域,指的是函数内部的空间,函数内部的变量,外部难以访问的地方
function doSomething(){
var blogName="xx";
function innerSay(){
alert(blogName);
}
innerSay();
}
alert(blogName); //脚本错误
innerSay(); //脚本错
作用域是分层的,内部作用域可以访问内部作用域中的变量,但反之则不行。
3. 块级作用域
ES5只有全局作用域而没有函数作用域,也没有块级作用域,这带来了很多不合理的场景。
在第一种情况下,内部变量可能会覆盖内部变量:
var tmp = new Date();
function f(){
console.log(tmp);
if(false){
var tmp = "hello";
}
}
f(); // undefined
上面的代码中,函数f执行后,输出结果是未定义的。 原因是变量增大,导致外层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 行:leta=b=0。 这句话确实声明了一个局部变量a。 但是,它确实声明了一个全局变量 b。
在 foo() 作用域或全局作用域中声明的变量 b 没有直接形式参数。 因此,JavaScript 将表达式 b=0 解释为 window.b=0。
b 是一个恰好被创建的全局变量。
在浏览器中,上面的代码片段相当于:
函数foo(){
leta;window.b=0;a=window.b;a++;
返回a;
foo();
typeofa;//=>'未定义'
typeofwindow.b;//=>'数字'
typeofa 是“未定义”。 变量 a 仅在 foo() 范围内声明,在外部范围内不可用。
typeofb 等于“数字”。 b 是一个值为 0 的全局变量。