JS的作用域相关知识(进阶——涉及标识符提升问题)

作用域:标识符(变量和函数名)在那些地方能够被访问 哪些地方就是这个标识符的作用域,对于函数来说,这些地方就是指的 函数的代码块内部和代码块外部

(标识符:var fn;function fn;其中fn就是标识符)

规则1:函数内部的代码可以访问函数内部的标识符,也可以访问函数外部的标识符

规则2:函数外部可以访问函数外部的标识符,但是不能访问函数内部的标识符

通常函数内部的标识符为局部标识符

案例:

<script>
    function fn () {	   	
		a=100 //未声明a,为a赋值,函数中找不到a,指向全局作用域下的a
        //如果改为 var a = 100 ,则为局部变量,不是外部的a
		}
		var a=200;
		fn()
		console.log(a) //100
</script>
<script>
    	function fn (a) {
		 //隐式操作 var a=300 隐式声明了局部变量a
				  a=100 //为局部变量a赋值
                console.log(a) //100
		}
		var a=200;
		fn(300)
		console.log(a) //200
</script>
<script>
    function fn (a) {
               //隐式声明形参a,并赋值实参给它 var a = 200
				  function fm (a) {
                    //隐式声明形参a,并赋值实参给它 var a = 200
		          console.log(a)// 200
				  	 a=90 //把a的值修改为90
		             console.log(a)//90
				  }
		         fm(a)//传入形参a,fm(200)
		 console.log(a)//虽然fm函数内作用域的a变化了,但是这里打印的是fn函数作用域内的a
                        //打印结果为200
		}
		var a=200;
		fn(a)//fn(200)
		console.log(a)//访问的是全局作用域下的a 200

//--------------------------------------------------------------------------------------
    var a = 200;
		function fn(a) {
			//隐式声明形参a,并赋值实参给它 var a = 200
			function fm() {
				console.log(a)//打印a,fm函数中无a,到上一作用域中寻找a 
                //打印200
				a = 90 //为a赋值,fm中无a,修改的是上一作用域中形参a
				console.log(a)//90 //打印a,fm函数中无a,到上一作用域中寻找a 
			}
			fm(a)//传入形参a,fm(200)
			console.log(a)// 此时形参a的值已经被修改
                          //打印90
		}		
		fn(a)//传入全局作用域下的a,fn(200)
		console.log(a)//200

</script>
<script>
    var total=0; //全局作用域下全局变量
		function  increment () {
		 var total=0 //increment函数内的局部变量
			  total=total+2
		}
		function  decrease() {
			  total=total-2 //操作total,但是decrease函数内无total变量,修改的是全局变量total
		}
        //函数调用一边,内部代码执行一遍
		increment()//total=0 + 2     //这里是局部变量total
		increment()//total=0 + 2    //这里是局部变量total
		decrease()	//total=0-2  //这里是全局变量
		console.log(total)//打印的是全局全局作用域下的total,无法访问函数内部的变量
                          //打印-2
</script>

标识符的隐式提升

每一个作用域在运行时,js引擎会先把作用域内部的关键字隐式提前扫描 并声明

函数也会隐式提升: 变量值提升声明,函数提升的是整个函数体

<script>
var a = 10//全局变量
		function fn() {
			//隐式声明var a,但是没有赋值
			console.log(a)//打印变量a只是声明了但是没有赋值打印结果为undefined
			a = 40//为a赋值
			var a = 20//修改a的值
			console.log(a)//打印结果为20
		}
		console.log(a)//打印全局变量,结果为10
		fn()//调用函数
		console.log(a)打印全局变量,结果为10

//----------------------------------------------------------------------------------
       //fn函数隐式提升
		fn() //调用 打印666
        fm() //报错
		function  fn () {
			console.log(666)
		}
</script>

练习:

<script>
        
    function fn (a) {
			//隐式声明形参 var a=外部函数
            //隐式提升函数fm
			fm=a //从新赋值
            //fm==>外部函数
			function fm () {
				console.log(124)
			}
			fm() //调用外部函数
		}		
		var a=function() {
			console.log(123)
		}
		fn(a)
		
</script>

 注意:对象内部的方法不会隐式提升

<script>
    	function fn () {
			console.log(obj.say) //找不到这个方法,报错			
			var obj={
				say:function(){} //对象内部的方法不会隐式提升
			}
		}
		fn()
</script>

同名标识符提升问题

变量名与函数名同名时:变量名先提升,函数再提升;

<script>
    console.log(a) //打印a函数
		var a=20
		function  a () {
			console.log(100)
		}
</script>

变量名与变量名相同时:先写先扫描(无意义)覆盖问题 就近访问

函数名与函数名相同时:先写先扫描,访问就近原则

<script>
    function fn () {
				console.log(111)
			}
			function fn () {
				console.log(2222)
			}			
			fn() //打印222
</script>

标识符的三种写法:

1、var a = 30;

2、function a(){}

3、function a(a){

//隐式操作:形参声明var a ;

}

实例:

<script>
    var a=20
		function fn(a){	
            //隐式操作声明形参:var a;
            //隐式操作声明局部变量a :var a;
            //把实参的值赋给形参:a=20;
            //函数隐式提升		
			console.log(a)//打印函数a
			a=90 //给a赋值为90
			console.log(a)//90
			var a=100 //把a的值改为100
			console.log(a) //100
			function  a () {
				console.log(6666)
			}
			console.log(a)//100			
		}
		fn(a) //fn(20)
</script>

执行顺序口诀:形(形参和变量)实函运(巧记)

它的指,在一个作用域的代码运行的时候 js引擎会执行代码的过程只有一个执行流程

流程:

1、先隐式提升当前作用域内部的所有形参变量和局部变量(只是声明提升,不提升赋值)

2、再把实参赋值给形参变量

3、然后执行函数的隐式提前声明

4、再按照代码顺序运行代码

函数执行的作用域问题:

函数是一个引用数据,标识符可以在任何作用域去引用一个函数,但是函数运行时的作用域在函数生成时所在的作用域。

简单来说就是函数运行时,是在写函数代码的地方运行代码,不是在调用函数的地方运行代码

例子:

<script>
    function fn(a) {
                //隐式声明形参 var a;
                //将实参的值赋值给形参 a=10
				function fm() {
					a = a + 1 //这里的a是fn函数内的形参a
					console.log(a)
				}
				return fm
			}
			var f1=fn(10) //得到一个函数返回值 为fm函数
			f1() //调用fm函数 打印11
            //fm函数写在fn函数内,所有它的作用域在fn函数内,而不是调用的全局作用域下
</script> 
<script>
    	function fn(a) {
                //var a = 10
				function fm() {
					a = a + 1 //这里的a是fn函数内的形参a
					console.log(a)
				}
				return fm
			}
			var f1=fn(10) //得到fm
			f1()//调用 打印11			
			var f2=fn(10) //从新调用fn 代码从新执行一次
			f2() //11
</script>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值