V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
Dummy
V2EX  ›  JavaScript

为什么说JS不支持块级作用域?

  •  
  •   Dummy · 2013-11-26 01:34:20 +08:00 · 7926 次点击
    这是一个创建于 4051 天前的主题,其中的信息可能已经有所发展或是发生改变。
    最近被Boss逼着学习Javascript,让我少看杂七杂八的书,从语法深入。

    《Javascript语言精粹》提到

    “Javascript的代码块语法看起来支持块级作用域,实际上JS并不支持,这个混淆之处可能成为错误之源。”

    有一点无法理解啊,函数作用域不就是块级作用域么,为什么说不支持?
    混淆可能导致什么错误呢?
    17 条回复    1970-01-01 08:00:00 +08:00
    Sivan
        1
    Sivan  
       2013-11-26 02:16:49 +08:00 via iPhone
    this 容易用错。
    otakustay
        2
    otakustay  
       2013-11-26 02:18:19 +08:00
    函数不是块,在语法中的block是指if/else/for/while语句里2个大括号之间的部分
    xuyiwei
        3
    xuyiwei  
       2013-11-26 08:33:58 +08:00
    是 花括号 {} 跟 java C# 这些用法不一样
    yimity
        4
    yimity  
       2013-11-26 09:12:06 +08:00
    @otakustay 回复的是正确的。
    coffeedeveloper
        5
    coffeedeveloper  
       2013-11-26 09:42:48 +08:00   ❤️ 1
    代码说明一切:
    ```
    var a = true;
    if(a){
    var b = 1;
    }
    alert(b) //输出1
    ```
    正常来说如果有块级作用域的话,```alert(b)```应该是输出```undefined```才对。
    Mutoo
        6
    Mutoo  
       2013-11-26 10:06:52 +08:00
    javascript:

    for(var i=0;i<10;i++){
    console.log(i); //0, 1, ..., 9
    }
    console.log(i); //10


    c++:

    for(int i=0;i<10;i++){
    cout<<i<<endl; //0, 1, ..., 9
    }
    cout<<i<<endl; // undeclared variable i
    GTim
        7
    GTim  
       2013-11-26 10:44:52 +08:00
    赞楼上几位
    teddy1004
        8
    teddy1004  
       2013-11-26 11:12:32 +08:00
    JavaScript 的作用域不太一样,作用域是被定义时候的作用域,而不是执行时的。

    function hello() {
    for (var i = 0; i < 10; i++) { doSomething... }
    }

    console.log(i);

    一般的语言上面的语法就是错误的,因为变量 i 应该已经被销毁了。但是 JS 中就是可以的。
    toctan
        9
    toctan  
       2013-11-26 11:48:56 +08:00
    @teddy1004 这代码明显会报错嘛,由于 JS 的 function scope, i 在函数外不可见,明显会报
    `ReferenceError: i is not defined`

    其实我觉得楼主是在问什么是 block scope 和 function scope
    Ricky123
        10
    Ricky123  
       2013-11-26 11:51:35 +08:00
    @coffeedeveloper 好遗憾,回复没有支持Markdown..
    cyberscorpio
        11
    cyberscorpio  
       2013-11-26 12:01:37 +08:00
    后来的标准里面有个 let 关键字支持这个的块级作用域。
    我在写 Firefox 扩展的时候已然大量使用了。
    Golevka
        12
    Golevka  
       2013-11-26 12:49:34 +08:00   ❤️ 2
    历史上, JS中的作用域是由activation object/variable object间的引用关系决定的, 所以只有在创建activation object时才会开启一片新的作用域, 这一动作发生在函数被调用时. (其实javascript能实现lexical scope是因为在declare function时先把parent scope给记下来, 这样每次调用函数时都能在正确的位置(F.[[Scope]])创建新的activation object)

    到了ES5时lexical env这块标准完全重做了, 用独立的environment record的概念来代替原有的object模拟scope的定义, 但是行为上基本还是兼容旧标准, 比如Block的求值规则几乎没变动; 到ES6这儿Block几乎完全重做了, 在进Block时会创建新的declarative environment, let和const的作用域解析就做在这个地方; var为了兼容旧标准在variable environment做名字解析.

    (其实到这里var这个东西就应该被干掉了, 或者至少标记为deprecated免得后人踩坑
    yjsslab
        13
    yjsslab  
       2013-11-26 13:22:03 +08:00
    用 js 写函数式编程的代码就应该问题不大吧.
    teddy1004
        14
    teddy1004  
       2013-11-26 14:50:42 +08:00
    @toctan 吐血。。。没注意写错地方了。。。好丢人
    coffeedeveloper
        15
    coffeedeveloper  
       2013-11-26 15:04:45 +08:00
    @Ricky123 好吧,其实我也想不懂为什么v2不支持markdown- -!
    Dummy
        16
    Dummy  
    OP
       2013-11-27 00:26:10 +08:00
    谢谢楼上的同学,终于明白了,其实这个问题持本质就是 @toctan 同学所说的,我没有把块级作用域和函数作用域弄清楚。
    FrankFang128
        17
    FrankFang128  
       2013-11-27 12:53:00 +08:00
    可以结合 hoisting (变量提升)一起理解 http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2832 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 13:14 · PVG 21:14 · LAX 05:14 · JFK 08:14
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.