跳至主要內容
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?

4563博客

全新的繁體中文 WordPress 網站
  • 首頁
  • 关于 js 闭包的联想,为什么匿名函数内的变量不能直接访问呢 具体看代码
未分類
29 12 月 2020

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

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

資深大佬 : sodadev 2

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

大佬有話說 (45)

  • 資深大佬 : cyrbuzz

    粘贴在控制台没啥报错。

  • 主 資深大佬 : sodadev

    很抱歉我不会格式化代码 = = 大家将就看一下吧 这个是 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

    你这问题不是很怪吗,设计上就是不能直接访问,所以不能直接访问

  • 主 資深大佬 : sodadev

    @cyrbuzz 是不报错 我在想为什么 console.log(Counter.privateCounter); 返回值会是 undefined

  • 主 資深大佬 : sodadev

    @des 我就是这个意思,。。。为什么设计成不能访问。。。

  • 資深大佬 : ck65

    先抛开闭包不想。

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

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

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

    这个变量不属于 Counter,它被匿名函数包在一个封闭的作用域里了。闭包二字说的就是这个作用域。

  • 主 資深大佬 : sodadev

    @ck65 谢谢指教! 那我再提问一下, 因为 Counter 这个对象只有一个匿名函数,但因为是匿名的函数 ,所以没法用 ”
    xx.xx ” 这种形式调用是么

  • 資深大佬 : ck65

    1 、JS 里函数本身也是 object,不管匿名不匿名
    2 、不是没法用 xx.xx ,相反可以,就像你对任意一个 object 去 xx.xx 一样

    感觉你的基础概念有点不熟,可以阅读一下《你不知道的 JS 》几本小册子,特别易懂。

  • 資深大佬 : vision1900

    避开闭包不谈,请问你能这么搞吗:
    var privateCounter = 0;
    var Counter = {
    increment: function() { changeBy(1); },
    decrement: function() { changeBy(-1); },
    value: function() { return privateCounter; }
    }

    // 现在你想

  • 資深大佬 : vision1900

    // 现在你想访问 Counter.privateCounter? Excuse Me?

  • 資深大佬 : shintendo

    啊这,虽然函数是对象,但从来没说过函数里面的变量是这个对象的属性吧?你为什么会得出这个结论

  • 主 資深大佬 : sodadev

    @ck65 谢谢指教!已经找到资源了!

  • 主 資深大佬 : sodadev

    @vision1900 #9 按照我目前的理解来说, 应该是不可以的。。
    我的理解是
    privateCounter 和 Counter 是同级的(同一个作用域)
    所以不可以去读取
    请问这样的理解对吗

  • 主 資深大佬 : sodadev

    @shintendo 请问! 那么这样说的话,函数的里的(指花括号里的)变量是不能被外部访问到的对吗,但是,函数可以使用它上一级作用域的变量,这样是对的吗

  • 資深大佬 : Kasumi20

    找一本书看看吧………………….

  • 資深大佬 : akira

    @shintendo 有没那个语言是把函数内变量,作为函数这个对象的属性的呢

  • 資深大佬 : johnkiller

    Counter 只是一个对象而已,只有最后 return 的三个属性。

  • 資深大佬 : ljpCN

    这个函数不是 Counter 的内容,这个函数的返回值才是 Counter 的内容。。函数被立即执行了。。

  • 資深大佬 : oott123

    你没有写 Counter.privateCounter = xxx,那么你就访问不了 Counter.privateCounter,就这么简单。
    至于函数里面的 var,那和 Counter 无关。

  • 資深大佬 : Zhuzhuchenyan

    混淆了太多概念,我来尝试指一条明路吧
    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 问题混淆,那是另一个大坑

  • 資深大佬 : iceheart

    14 的理解有点上路了,问题关键点是主对作用域概念理解不够。
    多数情况可以理解为花括号里边的变量 /代码不能被外部直接访问。对象算是有点例外。
    作用域基本是可见性的另一种说法。函数作用域、文件作用域。其他语言里有类作用域,对应 js 里的对象作用域。相关内容不多,关键词:作用域,可见性

  • 資深大佬 : beichenhpy

    不太懂 js 但我感觉你可以把有 privateCounter 这个变量的函数抽象出来,那么这样就可以看出来这个产量是局部的,外部没法访问到?

  • 資深大佬 : kiwier

    弄明白 js 作用域你就恍然大悟了,函数声明后如果没有执行是无法获知其内部的匿名函数的内部的,最多知道存在一个或者多个匿名函数,但是肯定不会知道自己内部的匿名函数里边的变量的,其内部的匿名函数在被执行的时候会生成自己的 ao 对象,外部函数才能通过匿名函数获取到内部变量

  • 資深大佬 : xiangyuecn

    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

    @sodadev 新手学闭包却实有点难啃,建议基础学透  http://www.jianxue.mobi/treep/2500/2775

  • 資深大佬 : dartabe

    建议把 javascript 的闭包从头开始看 不是什么三言两语说的清楚的

  • 資深大佬 : kiwier

    @dartabe 搞懂作用域,很容易理解闭包

  • 資深大佬 : dartabe

    @kiwier 我知道是作用域链的问题 但是还是看个来龙去脉比较容易懂

  • 資深大佬 : kiwier

    @dartabe 是的,作用域连 原型链 啥的

  • 資深大佬 : across

    这个就是基础的重要性了。

    外部变量不能访问 -> 变量作用域 -> 编译器的处理方式( OOP 语言会封装成类对象) -> 底层堆栈访问控制原则。
    但是认真看看 js 的书,前两个也会明确告诉你了。

  • 資深大佬 : px920906

    反过来想,如果是这样设计的
    “`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

    http://www.yinwang.org/blog-cn/2012/08/01/interpreter

  • 資深大佬 : v2lf

    var 是声明局部变量的,并添加到最近的作用域对象( js,我记得是都是函数作用域和全局)
    .运算符是访问对象属性的

  • 資深大佬 : v2lf

    建议看下 js 高级程序设计。

  • 資深大佬 : v2lf

    建议看下 js 高级程序设计。
    @v2lf 看下作用域链,还有原型链

  • 資深大佬 : user8341

    这个例子很经典的。就是用闭包实现封装,让外界访问不到 counter 的实现细节,只能访问到外部接口。实现细节就是 privateCounter 是匿名函数的内部变量,外部接口是匿名函数的返回值包含的那三个内部函数 inc 、dec 、val 。

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

    涉及到闭包的概念,三个内部函数之所以能访问到 var privateCounter 是因为它属于他们定义时的上下文环境。

  • 資深大佬 : user8341

    在一些语言比如 C++、Java 要实现封装很容易,只要访问控制声明成 private 就行了。但是 js 就是要绕一点。

  • 資深大佬 : ck65

    确实如 #18 @ljpCN 所说,Counter 的值是匿名函数返回的对象。我马虎了。但竟然也歪打正着。。总之最终赋给 Counter 的值,也就是 return 的那个对象里面没有 privateCounter 这个 key,访问一个对象里不存在的 key 就得到 undefined 。原因是作用域封闭( closure )这一思路还是有效。

  • 資深大佬 : meepo3927

    因为暴露接口更好,对比直接暴露成员变量,可以将代码修改对外部调用的影响降到最低。

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

    有了 value 接口,你就随便改了,甚至可以在 value 接口中写很多逻辑。

  • 資深大佬 : no1xsyzy

    那么,为了帮助主之类的新手,是否存在可以查看 js 变量作用域的( IDE 插件|独立演示用工具)?

  • 資深大佬 : 0x11901

    说句题外话,匿名函数和闭包本身就不是同一个概念

  • 資深大佬 : ck65

    @no1xsyzy 还真搜到一个差不多齐活的 visualizer https://ui.dev/javascript-visualizer/
    @sodadev 右边下方点击「 Complex Closures 」有惊喜 lol

  • 資深大佬 : cczeng

    作用域、执行上下文

  • 資深大佬 : theohateonion

    @no1xsyzy 不在词法作用域的变量是个 ide 都会报错了把

  • 資深大佬 : no1xsyzy

    @theohateonion 是直接显示范围,而不是得等有错才会报错

文章導覽

上一篇文章
下一篇文章

AD

其他操作

  • 登入
  • 訂閱網站內容的資訊提供
  • 訂閱留言的資訊提供
  • WordPress.org 台灣繁體中文

51la

4563博客

全新的繁體中文 WordPress 網站
返回頂端
本站採用 WordPress 建置 | 佈景主題採用 GretaThemes 所設計的 Memory
4563博客
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?
在這裡新增小工具