深入理解JavaScript的函数作用域

2019/04/10 10:10
阅读数 12

什么是作用域 ?

作用域:一个变量可以生效的范围。 变量不是在所有地方都可以使用的,而这个变量的使用范围就是我们要说的作用域。

注意:在JavaScript中,划分作用域也是用大括号划分的, 但是在 JS 之中能够有效限定作用域的大括号只有函数大括号!

有哪些作用域 ?

- 全局作用域(不再任何函数内)

学习使用作用域,以下内容是所需要了解的:

  • 全局作用域是最大的作用域
  • 在全局作用域中定义的变量可以在任何地方使用
  • 页面打开的时候,浏览器会自动给我们生成一个全局作用域 window
  • 这个全局作用域会一直存在,直到页面关闭才会销毁

请看下面示例代码:

1     var a = 10;
2     console.log(a);  // 输出结果: 10
3     function foo(){
4         console.log(a);  // 输出结果: 10
5     }
6     foo()

当变量 a 声明时,没有被函数大括号包裹, 那么这个变量我们称之为 全局变量

这个全局变量在任何地方都可以访问。

- 局部作用域(在函数内部)

同样的,以下内容也是所需要了解的:

  • 局部作用域就是在全局作用域下面开辟出来的一个相对小一些的作用域
  • 在局部作用域中定义的变量只能在这个局部作用域内部使用
  • 在 JS 中只有函数能生成一个局部作用域,别的都不行
  • 每一个函数,都是一个局部作用域

请看下面示例代码:

1     function foo(){
2         var a = 10; //在大括号之中声明的变量只能在这个大括号之中使用;
3         console.log(a); // 输出结果: 10
4     }
5     foo();
6     console.log(a); // 报错 => ReferenceError: a is not defined

通过上面示例代码可以看出:

在函数大括号之中声明的变量,这种变量我们称之为 局部变量 

局部变量只能在声明它的作用域之中使用;

我们见惯了常规情况,现在看一个特殊情况:

声明变量时不使用 var 关键字声明:

注意!这是一个不规范的声明方式!不要使用!不要使用!不用使用!

使用之后导致的结果就是:一个局部变量的声明,在全局中也可以被访问了!( 这样的声明叫做 伪全局变量 )

请看下面示例代码:

1   function foo(){
2         a = 10; // 此时声明变量 a 没有使用var关键字声明
3         console.log(a); // 10
4     }
5     foo();
6     console.log(a); // 输出 10,不报错了;

看完上面的代码示例,你是不是觉得这不挺好的嘛,变量 a 可以随便使用,都不用报错了,为什么不让使用??

呵呵,别高兴太早,继续往下看,你的这个想法很危险的!

当把局部变量变成伪全局变量:

你会发现:

  1. 生命周期变长,造成一定的负面影响;
  2. 占据了全局命名空间,造成不可预知的错误

是不是脑子里突然蹦出了好多问题:生命周期是什么鬼?命名空间又是什么鬼??

好吧,上面这个内容我说早了,那么接着往下看:

全局变量和局部变量的区别:

在这里就来聊一下上面的生命周期和命名空间吧!

生命周期(这个变量在内存之中存活的时间)

就是你啥时候可以访问!

- 全局变量:生命周期是和程序同步的, 程序不关闭,变量就一直存在;

导致的结果就是会让程序变得更重! 如果可能,还是少设计一点全局变量吧!对大家都好

- 局部变量:生命周期是和函数执行同步的,函数执行结束变量就被删除了;

现在知道啥是生命周期了吧,全局变量多了,可能真的会影响到我们程序的运行效率,上面说的伪全局变量就是这个道理。

我们看完了生命周期,再来一起看一下命名空间吧!

命名空间(变量名命名的唯一性)

- 全局变量:命名空间是唯一的,一个页面只有一个

我们先来举一个小例子,话不多说上代码:

 1     var count = 10;
 2     function foo(){
 3         // 我的代码 : 我的私人领域;
 4         // 程序的懒惰原则:函数的大括号之中如果已经有了查找结果,那么就不会继续再查找了;
 5         // 就近原则;
 6         var count = 0;
 7         console.log(count);  // 运行结果:0
 8     }
 9     foo();
10     console.log(count);  // 运行结果:10

为了解决全局之中的命名空间是唯一的这个问题,我们可以把这个变量放在局部,那么就不会占用全局的命名空间了。

- 局部变量:命名空间一个作用域一个

可以用匿名函数来解决命名空间的问题

最后一个问题:我现在要写一大坨代码,和别人的代码要配合 。 这个时候咋写呢???

我可以把代码写在一个没有名字的函数之中! 什么?这样写直接报错 ?
JS为啥阻止他 ? 如果我立即调用呢!来一个瞒天过海如何?

让匿名函数经历一次运算: 如果函数发生了特定的运算, 那么这个函数就会被当做一个地址;

 1     // 让匿名函数经历一次运算:  如果函数发生了特定的运算,那么这个函数就会被当做一个地址;
 2     // var res = 1 + function(){} 
 3     // console.log(res); //运行结果:1function(){}
 4     
 5     // 利用这个机制使用匿名函数立即调用 : 
 6     // +function(){
 7     //     console.log("hello world")
 8     // }();
 9     
10     // 函数经过运算变成了地址,被后面的调用运算符调用了;
11     // !function(){
12     //     console.log("hello world")
13     // }();
14 
15     // 一种普遍的写法 :
16         
17     // (function(){
18     //     console.log("hello world1");
19     // })()
20     // 可能存在的bug;
21     // (function(){
22     //     console.log("hello world1");
23     // })();  
24     // //两个匿名函数同时是使用一定要加上分号
25     // (function(){
26     //     console.log("hello world2");
27     // })();
28     // 建议写法;
29      ;(function(){
30          console.log("hello world1");
31      })();

 

最后来个总结吧!

1、全局不能访问局部

2、局部可以拿到全局

 


 

喜欢的朋友可以点点关注,点点赞,欢迎评论区留言互动。

原文出处:https://www.cnblogs.com/XH-jing/p/12386675.html

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部