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

4563博客

全新的繁體中文 WordPress 網站
  • 首頁
  • 关于词法作用域和闭包的一点疑问
未分類
26 3 月 2020

关于词法作用域和闭包的一点疑问

关于词法作用域和闭包的一点疑问

資深大佬 : Aloehuang 8

let a = 0;

function addone() { let a = 10; addtwo(); }

function addtwo() { let a = 20; addthree(); }

function addthree() { console.log(a); }

addone();

结果为 0,为什么不是 20 呢?不是说一层一层从调用上下文查找直到全局上下文吗?

大佬有話說 (38)

  • 資深大佬 : YadongZhang

    log 的是全局的 a,let 和 var 是不是有区别

  • 主 資深大佬 : Aloehuang

    我是从这里找到的词法作用域和闭包
    https://blog.hhking.cn/2018/09/08/i-never-understood-javascript-closures/

  • 資深大佬 : YadongZhang

    @Aloehuang #2 javascript.info 了解一下,有图解

  • 主 資深大佬 : Aloehuang

    @YadongZhang var 和 let 在这里没有区别,结果都是 0.
    你给的网站内容太多了,找不到具体要查找的问题

  • 資深大佬 : rabbbit

    js 的作用域是词法作用域,不是动态作用域.

  • 資深大佬 : secondwtq

    主所期望的行为恰恰是 Lexical Scoping 的反面,即 Dynamic Scoping
    把这两个的定义都找来,对比一下就能明白了

  • 資深大佬 : YadongZhang

    @Aloehuang #4 有搜索框,关键词 Closure,addThree() 调用的是全局 a,函数里的变量只能在函数块里使用,log 找不到的

  • 資深大佬 : ljpCN

    这个例子应该没有涉及闭包吧,闭包主要是把一些局部作用域的变量保持着不被回收掉。
    然后,这个你只看词法作用域就行了,只有 this 那种东西才要看运行时的调用吧。

  • 主 資深大佬 : Aloehuang

    @rabbbit 有没有这方面的文章可以看看?您这样说不是特别理解

  • 資深大佬 : rabbbit

    词法作用域: 在哪定义,在哪往上找变量
    静态作用域: 在哪调用,在哪往上找变量

  • 資深大佬 : rabbbit

    静态作用域 -> 动态作用域

  • 資深大佬 : rabbbit

    上边那个”静态作用域”写错了

    词法(静态)作用域: 在哪定义,在哪往上找变量
    动态作用域: 在哪调用,在哪往上找变量

  • 資深大佬 : Dyon

    全局有一个 a,前两个函数又在自己的作用于中定义了一个新的 a,当他们调用名为 a 的变量的时候会现在自己的作用域中找,找到了就调用它,这时候全局的那个 a 就被忽略了。第三个函数的作用域中没有名为 a 的变量,于是它调用了全局的 a 。这里用 let 还是 var 结果是一样的因为这里都是函数,如果是在 for 等块级语法中,let 和 var 才会不一样。

  • 主 資深大佬 : Aloehuang

    @secondwtq 谢谢,一针见血

  • 主 資深大佬 : Aloehuang

    @Dyon 那第三个函数为什么不从第二个函数里面找 a

  • 資深大佬 : mrcode

    JavaScript 是词法作用域,不是动态作用域

  • 資深大佬 : YadongZhang

    @Aloehuang #15 全局 a 注释掉,其他两个函数体都加一个 console.log(a) 就有答案了

  • 資深大佬 : Dyon

    @Aloehuang 哦刚刚误解主的问题了,主应该是想问动态作用域与静态作用域,不过即使不了解这些,根据运行结果也能推断出来 js 的作用域链是根据定义的位置确定而非调用的位置,是静态的

  • 資深大佬 : huangbangsheng

    高性能 JavaScript 开篇解释了你的问题

  • 資深大佬 : zhengjian

    @YadongZhang 全局 a 注释掉就报错了

  • 資深大佬 : YadongZhang

    @zhengjian #20 所以说 addThree() 函数里的 a 和其他两个函数体的 a 没有关系

  • 資深大佬 : Junh

    @ljpCN 建议重新看闭包

  • 資深大佬 : whoami9894

    你对比一下

    let a = 0;
    let addone = () => { let a = 10; addtwo(); }
    let addtwo = () => console.log(a);
    addone()

    /*===*/

    let a = 0;
    let addone = () => { let a = 10; let addtwo = () => console.log(a); addtwo(); }
    addone()

  • 資深大佬 : xiaoming1992

    为什么要研究这样的东西?明明一个 use strict 就能解决的问题

  • 資深大佬 : ZehaiZhang

    面试题吧,考察对 js 作用域的理解=

  • 資深大佬 : leihongtao1230

    作用域和执行栈不是一个概念啊

  • 資深大佬 : iMusic

    词法作用域是在写代码时,函数的位置确定的

  • 資深大佬 : autoxbc

    @Junh #22 这里确实没有闭包,不要看到闭合结构包着一个变量就说闭包

  • 資深大佬 : ljpCN

    @Junh

  • 資深大佬 : zackwan95

    你把代码写成这样在我们组 code review 都过不去,我最不明白国内的一点就是拿这些要么是错误要么是极差的代码当作考题。唯一的答案不应该是永远别写成这样么

  • 資深大佬 : xieranmaya

    函数里对变量的访问仅仅取决于函数的定义位置,不取决于函数的调用位置(这才是词法作用域的关键)。
    具体来说,你的 addthree 函数不管在哪调用(就算是被引擎调用),他都之访问到外面这个 a 。

  • 主 資深大佬 : Aloehuang

    @whoami9894 谢谢,上午抽空继续学习了下,理解了。我其实是把变量查找的原理(词法作用域)和执行栈、执行上下文混在一起了。
    你上面那段代码在 addtwo 中没有找到 a,于是从父级执行上下文寻找,但这个父级执行上下文有两种理解方式:第一种,执行上下文栈层面上的父级,也就是从哪个函数调用那么该函数就是父级执行上下文;第二种,作用域链层面上的父级(或者词法层面上的父级)。虽然有执行上下文栈,每调用一个函数就生成新的执行上下文并压入栈中,但是作用域链并不是和执行上下文栈一一对应的,作用域链由词法作用域导出,通常作用域链长度小于等于执行上下文栈的长度。
    上面那段代码在 addtwo 中没有找到 a,就从父级执行上下文找,但 addone 和 addtwo 实际上在词法层面上是同级的,所以这个父级执行上下文就是全局执行上下文。自然输出 0 。
    下面的父级执行上下文是 addone 函数执行时创建的执行上下文,所以输出 10 。

  • 主 資深大佬 : Aloehuang

    @xiaoming1992 不是 use strict 的问题

  • 主 資深大佬 : Aloehuang

    @leihongtao1230 对啊,我搞混了,现在清晰了很多。大佬一针见血说出了我迷惑的地方。

  • 主 資深大佬 : Aloehuang

    @zackwan95 真写代码肯定不会这样写啊,只是面对和自己预期不相符的结果时,是不是应该探究一下为什么和预期不符呢。要是真写代码这样写自己都会疯掉,无时无刻不要注意 js 语言的规则。

  • 資深大佬 : Junh

    @autoxbc 亲,这里建议您看下闭包的定义呢

  • 資深大佬 : lbw

    词法作用域是 compiling/parsing 期间确定,而不是运行时

  • 資深大佬 : xiaoming1992

    @Aloehuang 好吧,我原本以为”use strict”会管这些,原来不管,那就添加 eslint 规则,no-redeclare 。

    我的意思是,不管结果怎么样,这样的代码根本就不应该出现。

文章導覽

上一篇文章
下一篇文章

AD

其他操作

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

51la

4563博客

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