你的位置:首页 > Java教程

[Java教程]ES6: 参数默认值及中间域


下午看了一章 ECMA-262 by Dmitry Soshnikov, 现在稍稍来小结下ES6中的参数默认值以及由此产生的参数中间作用域。

原文地址: http://dmitrysoshnikov.com/ecmascript/es6-notes-default-values-of-parameters/#conditional-intermediate-scope-for-parameters

 

ES6中的参数默认值用法和其他语言都差不多,直接在参数后赋值:

1 function log(message, level = 'warning') {2  console.log(level, ': ', message);3 }4 5 log('low memory'); // warning: low memory6 log('out of memory', 'error'); // error: out of memory

不过和Python有一点不太相同的是,Python的默认值是在函数定义的时候计算的,然后作为函数的一个__defaults__参数保存下来。在函数执行时,对指向这个默认值的参数的操作也会导致默认值发生改变,

从而产生下面的问题:

 1 def foo(x = []): 2  x.append(1) 3  return x 4  5 # We can see that defaults are created once, when 6 # the function is defined, and are stored as 7 # just a property of the function 8 print(foo.__defaults__) # ([],) 9 10 foo() # [1]11 foo() # [1, 1]12 foo() # [1, 1, 1]13 14 # The reason for this as we said:15 print(foo.__defaults__) # ([1, 1, 1],)

解决方法是使用特殊常量None作为默认值,在函数内再判断并初始化为真正的默认值。

 1 def foo(x = None): 2  if x is None: 3   x = [] 4  x.append(1) 5  print(x) 6  7 print(foo.__defaults__) # (None,) 8  9 foo() # [1]10 foo() # [1]11 foo() # [1]12 13 print(foo.__defaults__) # ([None],)

 

ES6的实现是在函数每次调用是都执行一次默认值的计算,保证默认值不会在之前的执行过程中被更改。

 

参数的TDZ(Temporal Dead Zone)

ES6中提到的TDZ,指的是程序中,变量或者参数不能被访问直到初始化完成的区域。

因此在下面一段中,参数的默认值不能设置为参数本身。

1 var x = 1;2 3 function foo(x = x) { // throws!4  ...5 }

=x 中的默认值x,是在参数作用域中解析的,而不是全局的作用域。所以此时x是在TDZ中,因此不能访问,从而不能赋值给x本身作为默认值。

 

1 function foo(x, y = x) { // OK2  ...3 }

这种写法是可以的,因为在赋值给y之前,x已经被初始化为undefined了。

 

有条件的参数中间作用域


当至少有一个变量有默认值时,ES6定义了一个中间作用域来储存这些参数变量,同时这个作用域是不和函数主体的作用域共享的,这个是和ES5的一个主要的区别。

 1 var x = 1; 2  3 function foo(x, y = function() { x = 2; }) { 4  var x = 3; 5  y(); // is `x` shared? 6  console.log(x); // no, still 3, not 2 7 } 8  9 foo();10 11 // and the outer `x` is also left untouched12 console.log(x); // 1

在上面这种情况下,这里共有三个作用域:全局作用域,参数作用域,以及函数本体的作用域

1 : {x: 3} // inner2 -> {x: undefined, y: function() { x = 2; }} // params3 -> {x: 1} // global

此时函数y中,x的值是在自身的作用域,即参数作用域中解析的。

 

如果Transpiling(从一种语言编译到另一种相同抽象层次的语言)成ES5的话,这三层作用域就看的更清楚了:

 1 // ES6 2 function foo(x, y = function() { x = 2; }) { 3  var x = 3; 4  y(); // is `x` shared? 5  console.log(x); // no, still 3, not 2 6 } 7  8 // Compiled to ES5 9 function foo(x, y) {10  // Setup defaults.11  if (typeof y == 'undefined') {12   y = function() { x = 2; }; // now clearly see that it updates `x` from params13  }14 15  return function() {16   var x = 3; // now clearly see that this `x` is from inner scope17   y();18   console.log(x);19  }.apply(this, arguments);20 }

 

需要定义参数作用域的原因在于,函数类型的默认值,无论放在外部的作用域或者函数内部的作用域上执行,都会产生问题。

先看看如果是放在函数内部的作用域上执行的情况,

1 var x = 1;2 3 function foo(y = function() { return x; }) { // capture `x`4  var x = 2;5  return y();6 }7 8 foo(); // correctly 1, not 2

如果 function() { return x; } 放在函数内部的作用域执行,那么其中的x捕获的就会是函数内部的变量x(因为在VO的静态解析过程中,内部作用域上的x已经被定义了),但显然从理解上来说,函数中的x应该对应的是外部的x而非内部的(除非参数中还定义的一个同名的变量,然后覆盖了外部的同名变量)。由此看出,不将参数作用域和函数内部作用域共享的主要原因是:函数内部作用域中的同名变量不应该影响到参数闭包中所绑定的同名变量的值。

 

 

那如果放在外部的作用域上呢,

1 var x = 1;2 3 function foo(y, z = function() { return x + y; }) { // can see `x` and `y`4  var x = 3;5  return z();6 }7 8 foo(1); // 2, not 4

这是问题就会变成,function() { return x + y; }这个函数由于是在外部作用域上的,所以没有办法去访问到内部函数的参数了,即y的值访问不到,因为y不是定义在外部作用域上的。

 

那何谓“有条件的”中间作用域,就是当函数没有定义参数默认值的时候,是不会创建这个参数的中间作用域的,此时,参数绑定是和函数的内部作用域共享的,和在ES5的模式下的方式一致。

这种实现方式算是对ES5的下手动实现参数默认值的方式的一种兼容,使得能够在函数内部访问并修改函数参数中的变量,将他们放在相同的作用域中。

 

基本的内容就是这些了,这一部分的内容也并不多,但还是能看出不少语言设计时的构想以及对旧版本的兼容的考虑。自己写着写着算是把核心的内容都翻译了一遍,不过有些细节上的问题,也是非反复斟酌不能够理清其中的头绪的。

 

之后计划接着看 Lexical environments的部分,

http://dmitrysoshnikov.com/ecmascript/es5-chapter-3-1-lexical-environments-common-theory/#environment-frames-model

之前大概看了遍但不足以深入的理解,有不少名称的定义等感觉比较绕,看来,语义的这桩事情还是要靠语义才搞的定。

 

So far.




日本旅游团报价优惠日本蜜月旅游行程参考日本特价旅游多少钱到日本游费用报价大全日本自助游攻略20152015宝趣玫瑰节什么时候结束?从化宝趣玫瑰世界玫瑰节具体时间? 王莽岭景区怎么样?山西王莽岭景区介绍? 山西王莽岭自驾游路线?王莽岭旅游攻略? 五一沙湾美食街有什么活动?番禺沙湾美食攻略? 去香港玩有什么好吃的,可以介绍一下吗? 去香港买化妆品有哪些好的路线?在香港有哪些好的店? 香港迪士尼涨价的票价是多少?涨价的原因是什么? 去香港旅游刷银行卡方便吗? 在马尔代夫旅游要注意什么安全问题吗? 在马尔代夫旅游,中国人会吃不惯那边的食物吗? 马尔代夫机场有什么限制? 马尔代夫岛上的餐厅有哪几种? 2015三八妇女节深圳哪里有免费优惠活动?深圳欢乐谷3月好玩活动介绍? 2015欢乐谷元宵节夜场有什么好玩活动?深圳欢乐谷元宵节晚会介绍? 3月深圳有什么好玩地方?2015深圳欢乐谷好玩活动介绍? 2015放鸡岛三八妇女节女士免费吗?茂名放鸡岛3.8女士门票优惠价格? 08051C223KAZ2A Datasheet 08051C223KAZ2A Datasheet TAJB225K035RNJ Datasheet TAJB225K035RNJ Datasheet 04023J2R2BBWTR Datasheet 04023J2R2BBWTR Datasheet 泰国自助游攻略 泰国自助游攻略 泰国自助游攻略 澳门自助游攻略 澳门自助游攻略 澳门自助游攻略 柬埔寨是哪个国家 柬埔寨是哪个国家 柬埔寨是哪个国家