设为首页收藏本站|繁體中文

Project1

 找回密码
 注册会员
搜索
查看: 3147|回复: 3
打印 上一主题 下一主题

[原创发布] 简明易懂的变量作用域,闭包和匿名函数教程

[复制链接]

Lv3.寻梦者

梦石
0
星屑
1912
在线时间
1554 小时
注册时间
2013-4-13
帖子
917
跳转到指定楼层
1
发表于 2016-6-14 15:39:17 | 只看该作者 回帖奖励 |正序浏览 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有帐号?注册会员

x
本帖最后由 沉滞的剑 于 2016-6-14 15:40 编辑

我不是学编程的,这个教程只是用来帮助新手迅速理解这几个概念的,所以用词和理解肯定有不准确的地方,但是对于写脚本来说还是足够的。

1.变量的作用域
注意, 声明局部变量时要使用 var 关键词
否则js会默认将其设为window的成员,成为全局变量

例子1:
JAVASCRIPT 代码复制
  1. var a = 3;
  2. function foo(){
  3. var b = 3;
  4. console.log(a);
  5. console.log(b);
  6. }
  7. foo();
  8. console.log(a);
  9. console.log(b);
  10. 输出:3,3,3,undefined

结论1:在函数内部声明的变量b在函数外是访问不到的.
反过来在全局声明的变量对所有函数都是可见的

例子2:
JAVASCRIPT 代码复制
  1. function foo(){
  2.   var a = 3;
  3.   function fun(){
  4.   var b = 3;
  5.   console.log(a);
  6.   console.log(b);
  7.   }
  8.   fun();
  9.   console.log(a);
  10.   console.log(b);
  11. }
  12. foo();

输出:3,3,3,undefined
结论2:同样地, 局部函数内的变量对局部函数外是不可见的,
而函数内的函数对局部函数是可见的

也就是说在一对大括号{}里声明的变量对着这一层级内都是可见的
2. 闭包
如果我们想在外部读取局部变量的值,我们就需要用到闭包.
举例:
JAVASCRIPT 代码复制
  1. function foo(){
  2.     var n = 0;
  3.     return function fun(){
  4.     n++;
  5.     console.log(n);
  6.     }
  7. }
  8. a = foo(); //这里返回的是fun函数字面量
  9. a();
  10. a();
  11. a();
  12. foo()(); //这里()是一个运算符,代表运行的意思
  13. // 第一次运行了foo返回了fun,第二次代表运行fun.
  14. foo()();
  15. foo()();
  16. 输出: 1,2,3,1,1,1

注意a();输出的量都是递增的,证明了n这个变量在内存里是保留了的。
而foo()();是没有保留的,每次输出都是1.
这里有一个垃圾回收的机制。
因为foo()();运行结束后是没有变量指向它的所以它被回收了。
每一次呼叫都是创建的新对象,运行结束后就立刻被销毁。
而a()不是。它直接开辟了一块新内存来保存了这块数据。
所以fun函数会被保存。
而fun外面的函数foo也会被保存。局部变量n的值也会被记录。
我们通过return fun(){.....}来达到了访问foo的局部变量n的目的
这就是闭包。简单理解就是在域外访问域内的数据。
3.匿名函数
匿名函数, 简单说没有函数名的函数就是匿名函数。
匿名函数也同样遵守变量作用域的规则。
比如 function(){console.log('Hello World')}
其实它就是个函数字面量
但是字面量本身是无法被调用的,无法被调用怎么呼叫呢?
记得之前foo()()的用法么?
首先第一步,把函数字面量变成函数对象.
有很多方法:
常用的(function(){console.log('Hello World')})
我喜欢的方法!function(){console.log('Hello World')}
原理:将一个运算符放在旁边, 编译器会自动对字面量取值也就完成了转换.
但是,到这里这个函数只是被声明了而没有被运行
所以我们还需要一个()来运行它.
比如例子:
(function(){console.log('Hello World')})();
或者!function(){console.log('Hello World')}();
匿名函数在脚本里相当于一个壳, 在壳中声明的局部变量都不会被壳外访问到
这就避免了被污染.
但是壳中的数据可以通过闭包函数来访问, 它会被保存在内存里.
就比如说很多脚本的参数都是写在匿名函数里但是可以通过闭包来访问和修改

总结:
变量的访问是有层级的,内部函数可以访问外部变量,但外部函数不可以访问内部变量。
匿名函数是墙,把外部不需要知道和使用的数据包裹起来。
闭包是桥梁,通过返回闭包函数来访问和修改需要访问但是却在墙内的数据。




评分

参与人数 1星屑 +6 收起 理由
沧笙 + 6 精品文章

查看全部评分

夏普的道具店

塞露提亚-道具屋的经营妙方同人作品
发布帖:点击这里

Lv1.梦旅人

梦石
0
星屑
55
在线时间
69 小时
注册时间
2008-3-2
帖子
29
4
发表于 2016-10-6 17:15:54 | 只看该作者
教程太棒了,虽然并没有完全吃透,不过确实帮助我理解了不少。
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
50
在线时间
73 小时
注册时间
2016-4-6
帖子
39
3
发表于 2016-6-20 19:07:40 | 只看该作者
只看懂了一點 ..
  有打算最後將這系列的教學整合嗎?
如果這篇沒有進MV圖書館 , 就很難再有新人看到

点评

這個世紀絕症我也有...我明白的orz  发表于 2016-6-20 19:12
看情况, 想整合和修订以下的, 不过懒癌发作, so....  发表于 2016-6-20 19:10
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
60
在线时间
99 小时
注册时间
2011-11-20
帖子
12
2
发表于 2016-6-14 16:42:46 | 只看该作者
顶一个,现在很多大神都想着做游戏赚钱,少有教学贴了,另外用foo做例子,看着很别扭呢

点评

关于foo http://link.zhihu.com/?target=http%3A//zh.wikipedia.org/zh-cn/Foo  发表于 2016-6-20 19:36
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

站长信箱:[email protected]|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2024-11-11 05:31

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表