From 93d3b8593872d16530d94fc989121c046c87fc55 Mon Sep 17 00:00:00 2001 From: Ruan Yifeng Date: Thu, 25 Jun 2015 19:14:15 +0800 Subject: [PATCH] edit destructring --- docs/destructuring.md | 109 ++++++++++++++++++++++++++++++++---------- docs/function.md | 17 +++++-- 2 files changed, 97 insertions(+), 29 deletions(-) diff --git a/docs/destructuring.md b/docs/destructuring.md index 76f4781..874b6e6 100644 --- a/docs/destructuring.md +++ b/docs/destructuring.md @@ -45,7 +45,6 @@ tail // [2, 3, 4] ```javascript var [foo] = []; var [foo] = 1; -var [foo] = 'Hello'; var [foo] = false; var [foo] = NaN; var [bar, foo] = [1]; @@ -133,36 +132,14 @@ sixth // 5 上面代码中,fibs是一个Generator函数,原生具有Iterator接口。解构赋值会依次从这个接口获取值。 -## 字符串的解构赋值 - -由于JavaScript引擎内部,某些场合时,字符串会被转为类似数组的对象。因此,字符串也可以解构赋值。 - -```javascript -const [a, b, c, d, e] = 'hello'; -a // "h" -b // "e" -c // "l" -d // "l" -e // "o" -``` - -类似数组的对象都有一个length属性,因此还可以对这个属性结构赋值。 - -```javascript -let {length : len} = 'hello'; -len // 5 -``` - ## 对象的解构赋值 解构不仅可以用于数组,还可以用于对象。 ```javascript - var { foo, bar } = { foo: "aaa", bar: "bbb" }; foo // "aaa" bar // "bbb" - ``` 对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。 @@ -244,12 +221,11 @@ var x; ```javascript // 正确的写法 - -({x}) = {x:1}; -// 或者 ({x} = {x:1}); ``` +上面代码将整个解构赋值语句,放在一个圆括号里面,就可以正确执行。关于圆括号与解构赋值的关系,参见下文。 + 对象的解构赋值,可以很方便地将现有对象的方法,赋值到某个变量。 ```javascript @@ -258,6 +234,26 @@ let { log, sin, cos } = Math; 上面代码将Math对象的对数、正弦、余弦三个方法,赋值到对应的变量上,使用起来就会方便很多。 +## 字符串的解构赋值 + +字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。 + +```javascript +const [a, b, c, d, e] = 'hello'; +a // "h" +b // "e" +c // "l" +d // "l" +e // "o" +``` + +类似数组的对象都有一个length属性,因此还可以对这个属性解构赋值。 + +```javascript +let {length : len} = 'hello'; +len // 5 +``` + ## 函数参数的解构赋值 函数的参数也可以使用解构。 @@ -302,6 +298,67 @@ move(); // [0, 0] 上面代码是为函数move的参数指定默认值,而不是为变量x和y指定默认值,所以会得到与前一种写法不同的结果。 +## 圆括号问题 + +解构赋值虽然很方便,但是解析起来并不容易。对于编译器来说,一个式子到底是模式,还是表达式,没有办法从一开始就知道,必须解析到(或解析不到)等号才能知道。 + +由此带来的问题是,如果模式中出现圆括号怎么处理。解构赋值的规则是,只要有可能导致解构的歧义,就不得使用圆括号。 + +但是,这条规则实际上不那么容易辨别,处理起来相当麻烦。因此,建议只要有可能,就不要在模式中放置圆括号。 + +### 不能使用圆括号的情况 + +以下三种解构赋值不得使用圆括号。 + +(1)变量声明语句中,模式不能带有圆括号。 + +```javascript +// 全部报错 +var [(a)] = [1]; +var { x: (c) } = {}; +var { o: ({ p: p }) } = { o: { p: 2 } }; +``` + +上面三个语句都会报错,因为它们都是变量声明语句,模式不能使用圆括号。 + +(2)函数参数中,模式不能带有圆括号。 + +函数参数也属于变量声明,因此不能带有圆括号。 + +```javascript +// 报错 +function f([(z)]) { return z; } +``` + +(3)不能将整个模式,或嵌套模式中的一层,放在圆括号之中。 + +```javascript +// 全部报错 +({ p: a }) = { p: 42 }; +([a]) = [5]; +``` + +上面代码将整个模式放在模式之中,导致报错。 + +```javascript +// 报错 +[({ p: a }), { x: c }] = [{}, {}]; +``` + +上面代码将嵌套模式的一层,放在圆括号之中,导致报错。 + +### 可以使用圆括号的情况 + +可以使用圆括号的情况只有一种:赋值语句的非模式部分,可以使用圆括号。 + +```javascript +[(b)] = [3]; // 正确 +({ p: (d) } = {}); // 正确 +[(parseInt.prop)] = [3]; // 正确 +``` + +上面三行语句都可以正确执行,因为首先它们都是赋值语句,而不是声明语句;其次它们的圆括号都不属于模式的一部分。第一行语句中,模式是取数组的第一个成员,跟圆括号无关;第二行语句中,模式是p,而不是d;第三行语句与第一行语句的性质一致。 + ## 用途 变量的解构赋值用途很多。 diff --git a/docs/function.md b/docs/function.md index 74ea4ad..0af2472 100644 --- a/docs/function.md +++ b/docs/function.md @@ -565,7 +565,6 @@ var result = values.sort((a, b) => a - b); 下面是rest参数与箭头函数结合的例子。 ```javascript - const numbers = (...nums) => nums; numbers(1, 2, 3, 4, 5) @@ -575,7 +574,6 @@ const headAndTail = (head, ...tail) => [head, tail]; headAndTail(1, 2, 3, 4, 5) // [1,[2,3,4,5]] - ``` 箭头函数有几个使用注意点。 @@ -673,10 +671,23 @@ foo::bar; bar.call(foo); foo::bar(...arguments); -// 等同于 +i// 等同于 bar.apply(foo, arguments); ``` +箭头函数还有一个功能,就是可以很方便地改写λ微积分。 + +```javascript +// λ微积分的写法 +fix = λf.(λx.f(λv.x(x)(v)))(λx.f(λv.x(x)(v))) + +// ES6的写法 +var fix = f => (x => f(v => x(x)(v))) + (x => f(v => x(x)(v))); +``` + +上面两种写法,几乎是一一对应的。由于λ微积分对于计算机科学非常重要,这使得我们可以用ES6作为替代工具,探索计算机科学。 + ## 尾调用优化 ### 什么是尾调用?