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

javascript 的代码与 babel/es6 的代码执行时的一些问题

  •  
  •   Macya · 2016-10-15 21:28:55 +08:00 · 2591 次点击
    这是一个创建于 2750 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近在看 es6 入门教程,在函数的扩展那一章有这样一个例子:

    var x = 1;
    function foo (x, y = function(){x=1;}){
        var x = 3;
        y();
        console.log(x);
        // 3 选择 javascript 选项  (书中给出的答案是这个)
        // 1 选择 es6/babel 选项
    }
    foo();
    

    这个例子我是在 jsbin 上测试的,

    jsbin 的 js 代码填写处出可以选择 javascript 或者 es6/babel ,

    我选择 javascript 选项时上面的例子会输出打印 3 ,选择 es6/babel 选项时打印 1

    我想知道为什么这两个选项在处理 js 代码时又怎样的区别?

    假设以 javascript 那个选项的为标准 这个例子为什么最后会打印出 3 ?

    我个人的理解是(有错误希望能指出):赋予 y 变量的那个匿名函数在声明(定义?)时 foo 函数的作用域还未形成,也就是说在 foo 函数执行前,创建 foo 函数的执行上下文的时候,先完成 foo 函数中的参数声明,第一个参数是 X ,此时 x 赋值为 undefined ,第二个参数是 y , y 赋值为一个匿名函数,并且这个匿名函数在这个时候被声明(定义?),此时这个匿名函数保存了自己的作用域链,这个作用域链包含它自身声明的变量及 foo 函数参数中的 x ,还有 window 的活动对象。完成了参数变量的声明和赋值后,接下来是函数声明,然后时变量声明,这时新声明的 x 将参数声明中的 x 覆盖了,所以最后打印了 3 。

    6 条回复    2016-10-16 10:23:21 +08:00
    crs0910
        1
    crs0910  
       2016-10-15 22:07:53 +08:00
    babel 转换有问题吧,默认值写匿名函数,转到 foo 里面少了 var ,覆盖了 foo 里面的 x
    crs0910
        2
    crs0910  
       2016-10-15 22:11:08 +08:00
    事实上应该转成

    ```
    var x = 1
    function foo(x) {
    var y = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {
    var x = 1
    }
    var x = 3
    y()
    console.log(x)
    }
    foo()
    ```
    crs0910
        3
    crs0910  
       2016-10-15 22:50:56 +08:00
    看了一下, 这里的 foo 里面的 x 和 参数 y 默认值里面的 x 都是指的参数 x (也就是 undefined), 匿名函数里面对 x 赋值操作改变的是参数 x , foo 函数里面又声明了 var x 并赋值,这里的 x 已经不是参数 x 了(去掉 var 的话就还是参数 x ), 所以执行 y 并不会改变 foo 里面的 x
    crs0910
        4
    crs0910  
       2016-10-15 22:52:26 +08:00
    babel 转换的时候把参数里面的匿名函数扔 foo 里面去赋值了, x 就覆盖了
    Macya
        5
    Macya  
    OP
       2016-10-16 00:51:26 +08:00
    @crs0910 事实上,在 es6 入门教程中,作者也是提过:函数中新声明的变量如果与参数中的变量同名,这两个变量并不相同,也就是说函数中新声明的 x 与参数变量中的 x 并不是同一个 x 。但是对于这一点我不明白的是在新声明 x 之后, y 函数任然可以操作之前的参数变量 x ,难道可以理解为在 foo 函数作用域中同时存在一个参数变量 x 和一个变量声明 x ?而 y 函数中的作用域链只保存了参数变量 x ,新声明的 x 无论怎么操作都与 y 函数作用域链中的 x 互不干扰?

    又或者说,参数变量 y 在赋值匿名函数时产生了闭包,导致它保存的 x 不受外界干扰?但是这样一来,假设 foo 函数中没有新声明 x ,而是直接调用 x 进行赋值操作,(将"var x = 3" 改成 "x=3"),闭包的说法也就不妥当了。
    meszyouh
        6
    meszyouh  
       2016-10-16 10:23:21 +08:00 via Android
    https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/Default_parameters
    这里可能对你有帮助,前置参数对于后面参数可见的。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1395 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 17:44 · PVG 01:44 · LAX 10:44 · JFK 13:44
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.