JS之作用域链以及变量的声明提升

JS之作用域链以及变量的声明提升

JavaScript的作用域

  • 在Java,c等语言当中,作用域为for语句、if语句或{}内的一块区域,成为作用域
  • 而在JavaScript中,作用域为function(){}的区域,称为函数作用域,JS主要通过函数划分作用域
  • JS中的作用域又分为局部作用域全局作用域
  • 全局作用域:在script顶级写的变量和函数都是全局的,在外部文件顶级位置属性的变量和函数也是全局的。
<script>
var num=80   /*这是全局作用域*/
alert('num在外面输出的为'+num)  /*调用了全局作用域的num 值为80*/

function func(){
alert('num在里面输出的为'+num)
}
func()
</script>
  • 局部作用域:函数内部是独立的作用域 函数内的形参本质也是局部变量 函数的形参也只能在函数内访问,函数的外部我们无法访问
<script>
var num=80  
alert('num在外面输出的为'+num)

function func(){
var num =100   /*这是局部作用域*/
alert('num在里面输出的为'+num)  /*调用了局部作用域的num 值为100*/
}
func()
</script>

JavaScript的变量声明提升

JS中有变量声明这一个机制,当js在执行的时候,会分为两个阶段,一个是预解析,一个是执行,js预解析的时候会将所有用var声明的变量以及函数声明提升到当前作用域的最顶端,而赋值的语句在原地等待执行,预解析之后,再从上往下地逐行解析代码。

  • 平时我们写的var num=100;虽然代码只有1行,但是js会分成2个部分进行读取
//声明变量,并提升到作用域的最前面
var num;
//在原位进行赋值
num=100;
  • 我们写的代码,以为是从上往下执行的
var num =100
function func(){
console.log("第一次输出",num)   //第一次输出 undefined
var num=200
console.log("第二次输出",num)  //第二次输出  200
}
func()
  • 其实js真正的运行状态如下所示
  • 先把var 和function 声明预解析给提前了,再执行,而不是按照书写顺序从上往下执行
var num;
function func(){
var num;
console.log("第一次输出",num)   //第一次输出 undefined
num=200
console.log("第二次输出",num)  //第二次输出  200
}
num=100;
func();

注意:

  • 在JavaScript中,函数声明与变量声明经常被JavaScript引擎隐式地提升到当前作用域的顶部
  • 声明语句中的赋值部分并不会被提升,只有名称被提升了
  • 预解析的过程调试代码的时候断点并不会经过,因为断点调试的时候,预解析的代码已经运行完毕了
  • 函数声明的优先级会高于变量,如果变量名与函数名相同且未被赋值,则函数的声明会覆盖变量的声明
  • 如果函数有多个同名的参数,那么最后一个参数(即使没有定义)也会覆盖前面的同名参数

作用域链

作用域链:就是变量生效的范围和查找的规则

//全局变量  0级链
var num=123

function func1(){
// 1级链
var num=456
function fun2(){
//2级链
var num=789
}
}

练习代码

var num=111function func1(){
var num=222;
console.log(num) ;    /*num=????*/
function func2(){
num=333;
console.log(num);   /*num=????*/
}
func2()
console.log(num)  /*num=????*/
} 
console.log(num)  /*num=????*/
func1()

答案:

//0级链
var num=111function func1(){
//1级链
var num=222;
console.log(num) ;    /*num=222*/
function func2(){
//2级链
num=333;     /*这里直接覆盖了1级链的内容*/
console.log(num);   /*num=333*/
}
func2()
console.log(num)  /*num=333*/
} 
console.log(num)  /*num=111*/
func1()
  1. 函数内部优先访问函数内部的局部变量
  2. 如果函数内部没有,就会往上一层作用域查找
  3. 如果查找到了全局作用域,如果全局作用域都没有,就会报错xxx is not defined ,xxx变量没有定义。
    总结:就近原则 函数内部声明的变量,只能给函数内部来使用

为了解决预解析的问题
可以使用let变量和const变量两个新语法

  • var -声明变量,所有的浏览器都支持,但是小问题交多,比如预解析问题,变量名和函数名重名覆盖问题
  • Es6中新增了let声明变量和const声明常量,谷歌支持,IE8不支持
  • letconst并不会参与预解析,只有var有预解析

let变量和const变量
let:变量可以先进行声明,后赋值,或者声明的时候同时赋值。好处是–不参与预解析,代码从上往下按书写顺序执行,生成一个块级作用域。
const:常量声明的时候必须要进行赋值,赋值后值就不能被修改,修改的时候浏览器会出现报错。好处是防止未知的覆盖冲突,因为变量的覆盖没有任何的提示。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值