这是我参与2022首次更文挑战的第2天,活动详情查看:链接
一,什么是作用域
作用域指的是一个变量的作用范围
在JavaScript中,作用域分为全局作用域和函数作用域(局部作用域)
二,全局作用域
全局作用域是直接编写在script标签中的js代码,都在全局作用域
全局作用域在页面打开时候创建,在页面关闭时销毁
在全局作用域中,有一个全局对象window,window代表的是一个浏览器的窗口,他由浏览器创建我们可以直接使用。
在全局作用域中,创建的变量都会作为window对象的属性保存,都归window所有,创建的函数都变为window的方法。
全局作用域中的变量都是全局变量,在页面的任意部分都能使用的到(都能进行调用)。
例如:
var a = 10
var b = 20
console.log(window.a); //10
function fun(){
console.log('我是fun函数')
}
fun(); // === windown.fun()
#变量声明提前
使用var 关键字声明的变量,会在所有的代码执行之前被声明(但是没赋值)
但是如果声明时不加var 这变量不会被声明提前。
//使用var 相当于 在开始
// var a ;
console.log("a=" +a) //undefined
var a = 123
// 不使用var
console.log("a=" +a) //报错
a = 123
#函数声明提前
使用函数声明形式创建函数 function 函数名(){} ,他会在所有的代码执行之前就被创建(函数声明提前),所以我们可以在函数体之前调用。
函数表达式形式创建函数,不会被声明提前,所以不能在声明前执行。
需要等到代码执行到当前行数才进行赋值,所以,如果fun2在函数体fun2之前就执行,则会报undefined。
// fun 声明
fun(); //打印“我是fun函数”
function fun(){
console.log("我是fun函数")
}
fun2();//undefined
var fun2 = function(){
console.log("我是fun2函数")
}
fun2() // '我是fun2函数'
三,函数作用域(局部作用域)
函数作用域在调用函数时,创建函数作用域,函数执行完毕以后,函数作用域销毁
每调用一次函数,就会创建一次新的作用域,他们之间都是互相独立的。
在函数作用域中,可以访问到全局作用域的变量,反之,全局作用域访问函数作用域中的变量,则不行。
当在一个函数中操作一个变量时,他会现在自身作用域中寻找,直到找到全局作用域中。
如果全局中依然没有,则会报ReferenceErroe: xxx is not defined,
在函数中要访问全局变量,可以使用window对象
var a = 10;
function fun(){
console.log('a =' +a) // 10
}
fun();
//全局作用域访问函数作用域
function fun2 (){
var b = 20;
}
console.log(b),//'b is not defined'
//函数变量调用
function fun3(){
var a = '我是函数中的 a'
function fun4 (){
console.log('a =' +a) //我是函数中的 a
}
fun4();
console.log('a =' +a) //我是函数中的 a
}
fun3();
#函数声明提前特性
在函数中使用var关键字,会在函数中所有代码执行前被声明。
函数中的函数声明,也会在函数所有代码执行之前被执行。
例:
function fun5(){
//var a;
console.log(a); // a undefined
var a = 32;
fun6();//我是fun6
function fun6(){
console.log('我是fun6')
}
}
var c = 33
function fun7(){
console.log('c='+c)
var c = 10
}
fun7() //c? == undefined
// 如果把fun7 中的 c var去掉呢? c == ? c == 33
在函数外 console.log(c) ??
console.log(c) //10
//函数形参
var e = 111;
function fun8(e){
console.log(e) //??
}
由上代码,可以的到结论。函数中,不使用var 声明的变量都会变为全局变量,都归window所有。
函数有形参,则定义的形参提前,相当于
//函数形参
var e = 111;
function fun8(e){
var e;
console.log(e) //?? undefined
}
四,JavaScript预编译
首先JavaScript的执行过程会先扫描一下整体语法语句,如果存在逻辑错误或者语法错误,那么直接报错,程序停止执行,没有错误的话,开始从上到下解释一行执行一行。
由上全局作用域和局部作用域,我们可以总结出js预编译的步骤。
- 全局预编译
- 创建GO对象(Global Object)全局对象。
- 找变量声明,将变量名作为GO属性名,值为undefined
- 查找函数声明,作为GO属性,值赋予函数体
- 局部预编译
- 创建AO对象(Activation Object)执行期上下文。
- 找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
- 将实参值和形参统一。
- 在函数体里面找函数声明,值赋予函数体。
由于局部预编译(函数)中可能存在参数。所以比全局预编译多了实参形参相统一这步
GO对象是全局预编译,所以它优先于AO对象所创建和执行