关于 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; } } })();

4470 次点击
所在节点    JavaScript
45 条回复
cyrbuzz
2020-12-26 20:20:10 +08:00
粘贴在控制台没啥报错。
sodadev
2020-12-26 20:21:03 +08:00
很抱歉我不会格式化代码 = = 大家将就看一下吧 这个是 MDN 上的原版示例
var Counter = (function() {
var privateCounter = 0;
function changeBy(val) {
privateCounter += val;
}
return {
increment: function() { changeBy(1); },
decrement: function() { changeBy(-1); },
value: function() { return privateCounter; }
}
})();
des
2020-12-26 20:23:10 +08:00
你这问题不是很怪吗,设计上就是不能直接访问,所以不能直接访问
sodadev
2020-12-26 20:23:18 +08:00
@cyrbuzz 是不报错 我在想为什么 console.log(Counter.privateCounter); 返回值会是 undefined
sodadev
2020-12-26 20:24:10 +08:00
@des 我就是这个意思,。。。为什么设计成不能访问。。。
ck65
2020-12-26 20:35:31 +08:00
先抛开闭包不想。

Counter 是一个 object,所以你能 .privateCounter,这在语法上不犯规,所以不报错。

但 Counter 里没有 privateCounter 这个属性,所以读它就是 undefined 。

再回来看为什么 Counter 里没有 privateCounter 这个属性呢?因为这个对象的值是个匿名函数,仅仅是这个匿名函数里有个变量叫 privateCounter 而已。

这个变量不属于 Counter,它被匿名函数包在一个封闭的作用域里了。闭包二字说的就是这个作用域。
sodadev
2020-12-26 20:53:46 +08:00
@ck65 谢谢指教! 那我再提问一下, 因为 Counter 这个对象只有一个匿名函数,但因为是匿名的函数 ,所以没法用 "
xx.xx " 这种形式调用是么
ck65
2020-12-26 21:01:34 +08:00
1 、JS 里函数本身也是 object,不管匿名不匿名
2 、不是没法用 xx.xx ,相反可以,就像你对任意一个 object 去 xx.xx 一样

感觉你的基础概念有点不熟,可以阅读一下《你不知道的 JS 》几本小册子,特别易懂。
vision1900
2020-12-26 21:03:03 +08:00
避开闭包不谈,请问你能这么搞吗:
var privateCounter = 0;
var Counter = {
increment: function() { changeBy(1); },
decrement: function() { changeBy(-1); },
value: function() { return privateCounter; }
}

// 现在你想
vision1900
2020-12-26 21:03:41 +08:00
// 现在你想访问 Counter.privateCounter? Excuse Me?
shintendo
2020-12-26 21:33:46 +08:00
啊这,虽然函数是对象,但从来没说过函数里面的变量是这个对象的属性吧?你为什么会得出这个结论
sodadev
2020-12-26 21:40:24 +08:00
@ck65 谢谢指教!已经找到资源了!
sodadev
2020-12-26 21:45:19 +08:00
@vision1900 #9 按照我目前的理解来说, 应该是不可以的。。
我的理解是
privateCounter 和 Counter 是同级的(同一个作用域)
所以不可以去读取
请问这样的理解对吗
sodadev
2020-12-26 21:49:15 +08:00
@shintendo 请问! 那么这样说的话,函数的里的(指花括号里的)变量是不能被外部访问到的对吗,但是,函数可以使用它上一级作用域的变量,这样是对的吗
Kasumi20
2020-12-26 21:53:16 +08:00
找一本书看看吧......................
akira
2020-12-26 22:08:02 +08:00
@shintendo 有没那个语言是把函数内变量,作为函数这个对象的属性的呢
johnkiller
2020-12-26 22:19:47 +08:00
Counter 只是一个对象而已,只有最后 return 的三个属性。
ljpCN
2020-12-26 22:50:20 +08:00
这个函数不是 Counter 的内容,这个函数的返回值才是 Counter 的内容。。函数被立即执行了。。
oott123
2020-12-27 01:13:48 +08:00
你没有写 Counter.privateCounter = xxx,那么你就访问不了 Counter.privateCounter,就这么简单。
至于函数里面的 var,那和 Counter 无关。
Zhuzhuchenyan
2020-12-27 03:55:30 +08:00
混淆了太多概念,我来尝试指一条明路吧
1. 理解 Js 中对象和属性访问器的概念,参考阅读
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Property_Accessors

此处重点是要理解 JS 中一切皆是对象,并且对象中的属性和方法可以被属性访问器访问到

2. 理解什么是闭包,参开阅读
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures
此处需要重点理解词法作用域的概念,进而理解闭包的本质就是你持有的的某个可以被调用的函数会保持着自己作用域链(又称词法环境)的引用。

3. 理解 IIFE,参考阅读
https://developer.mozilla.org/zh-CN/docs/Glossary/立即执行函数表达式

4. 理解 var,参考阅读
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/var

此处重点其实是这句话,“用 var 声明的变量的作用域是它当前的执行上下文,它可以是嵌套的函数,或者对于声明在任何函数外的变量来说是全局。”

5. 在 1,2,3,4 的基础上就可以推导出,privateCounter 只是一个在匿名函数词法作用域中的一个变量,并且和对象没有任何关系

6. 你可能还会一知半解,延伸阅读推荐,you don't know js,有中文版,开源地址为
https://github.com/getify/You-Dont-Know-JS/tree/2nd-ed/scope-closures
这一章对词法作用域,作用域链,全局作用域,对象生命周期,闭包有详实的讲解

7. 千万别和 this 问题混淆,那是另一个大坑

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

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

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

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

© 2021 V2EX