解决javascript 作用域问题

1. 什么是作用域

任何编程语言都有作用域的概念,简单来说,作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期。js的作用域是靠函数来形成的,也就是说一个函数的变量在函数外不可以访问。

技巧顺口溜:

全局带var要提升
声明提升在最前
全局无var必赋值
无var赋值当全局
局部全局要区分
局部声明在局部
永远不可出局部
局部分清明暗var
局部无var是全局
局部有var是局部
全局无法访局部
赋值位置很重要
结果由它来决定
变量函数名相同
变量提升就消失

顺口溜,实际例子

1、全局带var要提升,声明提升在最前

			console.log(a);  // undefined
			var a = 20;
			console.log(a); // 20

变量提升后的代码:

<script>
			var a ;  


			console.log(a);
			a = 20;
			console.log(a);
			
</script>

分析:
(1) var 命名的全局变量会将其声明提升到全局作用域的最前面,可以假设将其提升至所有js代码的最前面
(2)只提升声明【var 变量名】,不提升变量赋值的位置

2、全局无var必赋值

			 a; 
			 console.log(a); // Uncaught ReferenceError: a is not defined
			 b = 10;
			console.log(b); // 10

分析
1、 a 由于没有var关键字且没有赋值,则报错
2、b没有var关键字但赋值了可以正常使用

3、无var赋值当全局

			a = 1;
			console.log(a == window.a); // true

分析:
因为window属性可以省略不写所以由上方的判等可以看出 a 属性全局变量

4、局部全局要区分

			var a = 1;  // 第一行
            function fun(){
				var a = 10; // 第三行
			}
			console.log(a); // 1

分析
(1)第一行的 var a 没在函数体内所以是全局变量
(2)第三行的 var a 由于在函数体内是局部变量
(3)由于作用域的问题全局不可以访问局部变量所以输出的是全局的a

5、局部声明在局部,永远不可出局部,局部分清明暗var

			var a = 1;
			var b = 2;
			function fun(a){
				a = 10;
				var b = 20;
			}
			console.log(a); // 1
			console.log(b); // 2

变量提升后的代码

			var a = 1;
			var b = 2;
			function fun(a){
				var a;
				var b;
				a = 10;
				b = 20;
			}
			console.log(a); // 1
			console.log(b); // 2

分析:
(1)由于函数有形参a可以假设在函数内部声明了一个var a 【暗var】所以函数中的 a = 10 看似是全局变量其实是局部变量
(2)局部变量的声明提升只能在局部中的最顶层且不能出局部作用域
(3)函数的形参的优先级高于函数内部声明的变量名的提升

6、局部无var是全局,局部有var是局部

			var a = 1;
			var b = 2;
			function fun(a){
				a = 10;
				b = 20;
			}
			console.log(a); // 1
			console.log(b); // 20

分析:

由于有形参 a 所以就在函数内部声明了一个 var a
由于函数内部没有声明 b 且 无形参 b ,所以局部的 b 就变成的全局变量 b

7、赋值位置很重要,结果由它来决定

			var b = 2;
			function fun(a){
				b = 20;
			}
			var b = 23;
			console.log(b); // 23

提升后的代码:

			var b;
			b = 2;
			function fun(a){
				b = 20;
			}
			 b = 23;
			console.log(b); // 23

分析:

虽然说变量名提升了,但是变量最后的结果却是由赋值的位置所决定的

8、变量函数名相同, 函数高于同变量

			var fn = 10;
			function fun(a){
				b = 20;
				console.log(b);
			}
			fn(); // Uncaught TypeError: fn is not a function

变量提升后的代码

			var fn = function fun(a){
				b = 20;
				console.log(b);
			}
			var fn;
			fn = 10;
			fn(); // Uncaught TypeError: fn is not a function

分析:
由于函数名和变量名相同,带函数名的函数会整体提升(包括函数体)且高于变量名的提升,所以最后将函数赋值为了 10 再次调用时实际上是在 10(); 所以报错位不是函数。

9、变量名赋值的函数,会将变量名提升但函数不可提升

			 a();  // Uncaught TypeError: a is not a function
			var a = function(){
				var a = 1;
				console.log(a);
			}
			a(); // 1

提升后的代码:

			 var a;
			 a();  // Uncaught TypeError: a is not a function
			 a = function(){
				var a = 1;
				console.log(a);
			}
			a(); // 1

10、立即执行函数【自调用函数】不会提升

			var a = 2;
			(function(){
				 a = 1;
				console.log(a);
			})();

11、作用域链

在函数中,用var声明的变量是函数的局部变量,如果访问的变量没有带var会去外界(上一层作用域)寻找带var
声明的变量,如果有就访问,如果没有会去上上层作用域继续去寻找,直到找到全局作用域,如果全局也没有用var定义的变量,就报错了,寻找的过程
形成的链条就是作用域链。

			 a = 0;
			function fn1(){
				function fn2(){
					function fn3(){
						function fn4(){
							console.log(a); // 0
						}
						fn4();
					}
					fn3();
				}
				fn2();
			}
			fn1();

12、同时赋值和同时进行赋值

  1. 同时赋值
			var a = 1;
			var b = 2;
			var c = 3;
			function fn(){
				var a,b,c;
				a = 10;
				b = 20;
				c = 30;
			}
			fn();
			console.log(a);  // 1
			console.log(b);  // 2
			console.log(c);  // 3

var a , b , c; 带逗号的赋值为同时赋值三个变量,所以函数体内的a b c 都变成了局部变量,外部无法访问

2、同时进行赋值

			var a = 1;
			var b = 2;
			var c = 3;
			function fn(){
				var a = b = c = 10;
			}
			fn();
			console.log(a);  // 1
			console.log(b);  // 10
			console.log(c);  // 10

var a = b = c = 10 等价于 : var a = 10; b = 10; c = 10;

由于 b , c 为 函数体内未带var所以为全局变量,所以改变了全局的 b c 值

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值