关于 js 闭包的联想,为什么匿名函数内的变量不能直接访问呢 具体看代码

2020-12-26 20:15:06 +08:00
 sodadev

var Counter = (function() { var privateCounter = 0; function changeBy(val) { privateCounter += val; } return { increment: function() { changeBy(1); }, decrement: function() { changeBy(-1); }, value: function() { return privateCounter; } } })();

4483 次点击
所在节点    JavaScript
45 条回复
iceheart
2020-12-27 08:21:54 +08:00
14 楼的理解有点上路了,问题关键点是楼主对作用域概念理解不够。
多数情况可以理解为花括号里边的变量 /代码不能被外部直接访问。对象算是有点例外。
作用域基本是可见性的另一种说法。函数作用域、文件作用域。其他语言里有类作用域,对应 js 里的对象作用域。相关内容不多,关键词:作用域,可见性
uselessVisitor
2020-12-27 08:58:56 +08:00
不太懂 js 但我感觉你可以把有 privateCounter 这个变量的函数抽象出来,那么这样就可以看出来这个产量是局部的,外部没法访问到?
kiwier
2020-12-27 09:20:12 +08:00
弄明白 js 作用域你就恍然大悟了,函数声明后如果没有执行是无法获知其内部的匿名函数的内部的,最多知道存在一个或者多个匿名函数,但是肯定不会知道自己内部的匿名函数里边的变量的,其内部的匿名函数在被执行的时候会生成自己的 ao 对象,外部函数才能通过匿名函数获取到内部变量
xiangyuecn
2020-12-27 09:48:02 +08:00
var Counter = (function() {
//var privateCounter = 0;
function changeBy(val) {
Counter.privateCounter = (Counter.privateCounter||0) +val;
}
return {
increment: function() { changeBy(1); },
decrement: function() { changeBy(-1); },
value: function() { return Counter.privateCounter; }
}
})();

变量谁要就给谁,不然函数里面的除了自己能访问谁都访问不了。特例是全局下面的,被划给了 window 对象
hujun528
2020-12-27 10:54:27 +08:00
@sodadev 新手学闭包却实有点难啃,建议基础学透  http://www.jianxue.mobi/treep/2500/2775
dartabe
2020-12-27 11:37:20 +08:00
建议把 javascript 的闭包从头开始看 不是什么三言两语说的清楚的
kiwier
2020-12-27 12:08:02 +08:00
@dartabe 搞懂作用域,很容易理解闭包
dartabe
2020-12-27 12:19:03 +08:00
@kiwier 我知道是作用域链的问题 但是还是看个来龙去脉比较容易懂
kiwier
2020-12-27 12:57:31 +08:00
@dartabe 是的,作用域连 原型链 啥的
across
2020-12-27 13:00:51 +08:00
这个就是基础的重要性了。

外部变量不能访问 -> 变量作用域 -> 编译器的处理方式( OOP 语言会封装成类对象) -> 底层堆栈访问控制原则。
但是认真看看 js 的书,前两个也会明确告诉你了。
px920906
2020-12-27 13:09:47 +08:00
反过来想,如果是这样设计的
```js
function sayHello(name) {
var hello = 'Hello'
console.log(hello + ' ' + name)
}
sayHello.hello = 'Fxck you'
sayHello('Jack')
```
就完全可以写成
```js
var hello = 'Hello'
function sayHello(name) {
console.log(hello + ' ' + name)
}
hello = 'Fxck you'
sayHello('Jack')
```
闭包、局部变量不就没什么意义了么,都用全局变量好了
FaiChou
2020-12-27 17:04:19 +08:00
v2lf
2020-12-27 17:40:18 +08:00
var 是声明局部变量的,并添加到最近的作用域对象( js,我记得是都是函数作用域和全局)
.运算符是访问对象属性的
v2lf
2020-12-27 17:40:52 +08:00
建议看下 js 高级程序设计。
v2lf
2020-12-27 17:41:25 +08:00
建议看下 js 高级程序设计。
@v2lf 看下作用域链,还有原型链
user8341
2020-12-27 19:07:28 +08:00
这个例子很经典的。就是用闭包实现封装,让外界访问不到 counter 的实现细节,只能访问到外部接口。实现细节就是 privateCounter 是匿名函数的内部变量,外部接口是匿名函数的返回值包含的那三个内部函数 inc 、dec 、val 。

counter 是什么?是匿名函数的返回值,Counter = (function() {...}) (); 注意看,它定义了这个函数对象,然后立刻就调用它,返回值赋给 Counter 。

涉及到闭包的概念,三个内部函数之所以能访问到 var privateCounter 是因为它属于他们定义时的上下文环境。
user8341
2020-12-27 19:08:51 +08:00
在一些语言比如 C++、Java 要实现封装很容易,只要访问控制声明成 private 就行了。但是 js 就是要绕一点。
ck65
2020-12-27 19:33:04 +08:00
确实如 #18 @ljpCN 所说,Counter 的值是匿名函数返回的对象。我马虎了。但竟然也歪打正着。。总之最终赋给 Counter 的值,也就是 return 的那个对象里面没有 privateCounter 这个 key,访问一个对象里不存在的 key 就得到 undefined 。原因是作用域封闭( closure )这一思路还是有效。
meepo3927
2020-12-28 09:28:08 +08:00
因为暴露接口更好,对比直接暴露成员变量,可以将代码修改对外部调用的影响降到最低。

假如有一天,因为一些原因,你要改成员变量( privateCounter )的名字,如果没有 value 接口的话,外部调用者岂不是都要改。

有了 value 接口,你就随便改了,甚至可以在 value 接口中写很多逻辑。
no1xsyzy
2020-12-28 09:29:30 +08:00
那么,为了帮助楼主之类的新手,是否存在可以查看 js 变量作用域的( IDE 插件|独立演示用工具)?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/739259

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX