最近在看 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 。
1
crs0910 2016-10-15 22:07:53 +08:00
babel 转换有问题吧,默认值写匿名函数,转到 foo 里面少了 var ,覆盖了 foo 里面的 x
|
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() ``` |
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
|
4
crs0910 2016-10-15 22:52:26 +08:00
babel 转换的时候把参数里面的匿名函数扔 foo 里面去赋值了, x 就覆盖了
|
5
Macya OP @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"),闭包的说法也就不妥当了。 |
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
这里可能对你有帮助,前置参数对于后面参数可见的。 |