【重学JS】-4,作用域

135 阅读4分钟

这是我参与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预编译的步骤。

  • 全局预编译
  1. 创建GO对象(Global Object)全局对象。
  2. 找变量声明,将变量名作为GO属性名,值为undefined
  3. 查找函数声明,作为GO属性,值赋予函数体
  • 局部预编译
  1. 创建AO对象(Activation Object)执行期上下文。
  2. 找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
  3. 将实参值和形参统一。
  4. 在函数体里面找函数声明,值赋予函数体。

由于局部预编译(函数)中可能存在参数。所以比全局预编译多了实参形参相统一这步

GO对象是全局预编译,所以它优先于AO对象所创建和执行