LiveScript 流程控制、循环以及列表推导式

时间:2021-03-11 13:46:07

The LiveScript Book

 
 

The LiveScript Book

Generators and Yield

你可以在你的 LiveScript 代码中使用 Ecmascript 2015 中的的generatorsyield了!

1.function* f
2. yield \foo
3.
4.g = ->*
5. yield from f!
6. yield \bar
7.
8.h = g!
9.
10.h.next!.value + h.next!.value # => "foobar"

1.var g, h;
2.function* f(){
3. return (yield 'foo');
4.}
5.
6.g = function*(){
7. (yield* f());
8. return (yield 'bar');
9.};
10.h = g();
11.h.next().value + h.next().value;

你可以同过在function关键字后加*或者在箭头后加*来创建generators,对我们已经有的各种箭头,依然可以正常工作。

yieldjavascript 中的yield一样的,yield from等价于 JavaScript 中的yield*

If and Unless

有几种格式来使用if语句(if语句实际上是一个表达式,你可以按照表达式的方式去使用)。

1.if 2 + 2 == 4
2. 'something'
3.else
4. 'something else'
5.
6.if 2 + 2 == 4 then 'something' else 'something else'
7.
8.if 2 + 2 == 4
9.then 'something'
10.else 'something else'

1.if (2 + 2 === 4) {
2. 'something';
3.} else {
4. 'something else';
5.}
6.if (2 + 2 === 4) {
7. 'something';
8.} else {
9. 'something else';
10.}
11.if (2 + 2 === 4) {
12. 'something';
13.} else {
14. 'something else';
15.}

else是可选的,else if也是可以被允许的。

1.if 2 + 2 == 4
2. 'something'
3.
4.if 2 + 2 == 6
5. 'something'
6.else if 2 + 2 == 5
7. 'something else'
8.else
9. 'the default'

1.if (2 + 2 === 4) {
2. 'something';
3.}
4.if (2 + 2 === 6) {
5. 'something';
6.} else if (2 + 2 === 5) {
7. 'something else';
8.} else {
9. 'the default';
10.}

if语句可以被用作表达式:

1.result = if 2 / 2 is 0
2. then 'something'
3. else 'something else'

1.var result;
2.result = 2 / 2 === 0 ? 'something' : 'something else';

你也可以后置使用if,它比赋值运算的优先级低,使得如下可行:

1.x = 10
2.x = 3 if 2 + 2 == 4
3.x # => 3

1.var x;
2.x = 10;
3.if (2 + 2 === 4) {
4. x = 3;
5.}
6.x;

unless等价于if not

1.unless 2 + 2 == 5
2. 'something'
3.
4.x = 10
5.x = 3 unless 2 + 2 == 5

1.var x;
2.if (2 + 2 !== 5) {
3. 'something';
4.}
5.x = 10;
6.if (2 + 2 !== 5) {
7. x = 3;
8.}

that指向语义中的值,并且会进行存在检查。

1.time = days: 365
2.
3.half-year = that / 2 if time.days
4.# => 182.5
5.
6.if /^e(.*)/ == \enter
7. that.1 # => 'nter'
8.
9.if half-year?
10. that * 2
11.# => 365

1.var time, that, halfYear;
2.time = {
3. days: 365
4.};
5.if (that = time.days) {
6. halfYear = that / 2;
7.}
8.if (that = /^e(.*)/.exec('enter')) {
9. that[1];
10.}
11.if ((that = halfYear) != null) {
12. that * 2;
13.}

循环和推导式

for循环有三种基本形式。一个是在范围内迭代,一个是在列表内迭代,最后一个是通过键值对对对象进行迭代。

我们先来看看for基于范围的迭代,它的基本形式是这样的:
for (let) (VAR) (from NUM) (to|til NUM) (by NUM) (when COND)(几乎都是可选的)。

let会把循环体包进一个函数体内,然后会在循环时自动调用此函数。这个使得函数闭包非常方便。同时也可以使得你循环体中的变量不会暴露到循环外面!

from后接一个数字表示计数器从此数开始计数,省略from,默认是0

to或者til后接循环计数器的终止边界值。to表示少于等于,til表示严格少于。

by是步长,默认是1

whencase,|的语法糖)是一个可选的循环守护。

如果把for用作一个表达式,那么将返回一个list

1.ret = for i from 1 to 10 by 3
2. i
3.ret # => [1, 4, 7, 10]

1.var ret, res$, i$, i;
2.res$ = [];
3.for (i$ = 1; i$ <= 10; i$ += 3) {
4. i = i$;
5. res$.push(i);
6.}
7.ret = res$;
8.ret;

for...in对一个列表进行迭代。其结构是这样的:
for (let) (VAL-VAR) (, INDEX-VAR) in EXP (by NUM) (when COND)
再一次几乎所有的都是可选的。letbywhen跟前面讲的还是一样的。

VAL-VAR是当前列表项的值,INDEX-VARVAL-VAR所对应的下标索引值,任何一个都是可选的。

EXP得是一个数组。

1.for x in [1 2 3]
2. x
3.
4.xs = for let x, i in [1 to 10] by 2 when x %3 is 0
5. -> i + x
6.
7.xs[0] # => 5
8.xs[1] # => 17

1.var i$, ref$, len$, x, xs, res$;
2.for (i$ = 0, len$ = (ref$ = [1, 2, 3]).length; i$ < len$; ++i$) {
3. x = ref$[i$];
4. x;
5.}
6.res$ = [];
7.for (i$ = 0, len$ = (ref$ = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).length; i$ < len$; i$ += 2) {
8. if (ref$[i$] % 3 === 0) {
9. res$.push((fn$.call(this, i$, ref$[i$])));
10. }
11.}
12.xs = res$;
13.xs[0];
14.xs[1];
15.
16.function fn$(i, x) {
17. return function() {
18. return i + x;
19. };
20.}

for...of用来对一个对象进行迭代。结构是这样的:
for (own) (let) (KEY-VAR) (, VAL-VAR) of EXP (when COND)

又一次机会都是可选的,letwhen跟前面的一样。

own使用hasOwnProperty来检查属性,阻止对原型链上的属性进行迭代。

KEY-VAR是属性名,VAL-VAR是属性值,二者也都是可选的。

EXP得是一个对象。

1.for k, v of {a: 1, b: 2}
2. "#k#v"
3.
4.xs = for own let key, value of {a: 1, b: 2, c: 3, d: 4}
5. when value % 2 is 0
6. -> key + value
7.
8.xs[0]! # => 'b2'
9.xs[1]! # => 'd4'

1.var k, ref$, v, xs, res$, i$, own$ = {}.hasOwnProperty;
2.for (k in ref$ = {
3. a: 1,
4. b: 2
5. }) {
6. v = ref$[k];
7. k + "" + v;
8.}
9.res$ = [];
10.for (i$ in ref$ = {
11. a: 1,
12. b: 2,
13. c: 3,
14. d: 4
15. })
16. if (own$.call(ref$, i$)) {
17. if (ref$[i$] % 2 === 0) {
18. res$.push((fn$.call(this, i$, ref$[i$])));
19. }
20. }
21.xs = res$;
22.xs[0]();
23.xs[1]();
24.
25.function fn$(key, value) {
26. return function() {
27. return key + value;
28. };
29.}

循环嵌套的返回值也是相同结构的列表嵌套。

1.result = for x to 3
2. for y to 2
3. x + y
4.result
5.# => [[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5]]

1.var result, res$, i$, x, lresult$, j$, y;
2.res$ = [];
3.for (i$ = 0; i$ <= 3; ++i$) {
4. x = i$;
5. lresult$ = [];
6. for (j$ = 0; j$ <= 2; ++j$) {
7. y = j$;
8. lresult$.push(x + y);
9. }
10. res$.push(lresult$);
11.}
12.result = res$;
13.result;

你可以在在in/of循环中省略一个或两个变量:

1.res = for , i in [1 2 3]
2. i
3.res # => [0, 1, 2]
4.
5.for til 3 then func!
6.
7.# calls func three times
8.
9.[6 for til 3] # => [6, 6, 6]

1.var res, res$, i$, len$, i;
2.res$ = [];
3.for (i$ = 0, len$ = [1, 2, 3].length; i$ < len$; ++i$) {
4. i = i$;
5. res$.push(i);
6.}
7.res = res$;
8.res;
9.for (i$ = 0; i$ < 3; ++i$) {
10. func();
11.}
12.for (i$ = 0; i$ < 3; ++i$) {
13. 6;
14.}

列表推导式总是生成一个列表。列表中的循环嵌套生成的列表还是一维的。

1.[x + 1 for x to 10 by 2 when x isnt 4]
2.# => [1, 3, 7, 9, 11]
3.
4.
5.["#{x}#{y}" for x in [\a \b] for y in [1 2]]
6.
7.# => ['a1', 'a2', 'b1', 'b2']

1.var i$, x, ref$, len$, j$, ref1$, len1$, y;
2.for (i$ = 0; i$ <= 10; i$ += 2) {
3. x = i$;
4. if (x !== 4) {
5. x + 1;
6. }
7.}
8.for (i$ = 0, len$ = (ref$ = ['a', 'b']).length; i$ < len$; ++i$) {
9. x = ref$[i$];
10. for (j$ = 0, len1$ = (ref1$ = [1, 2]).length; j$ < len1$; ++j$) {
11. y = ref1$[j$];
12. x + "" + y;
13. }
14.}

你可以使用空白格来使得列表推到式更优美。

1.[{id: id1, name, age} for {id: id1, name} in table1
2. for {id: id2, age} in table2
3. when id1 is id2]

1.var i$, ref$, len$, ref1$, id1, name, j$, len1$, ref2$, id2, age;
2.for (i$ = 0, len$ = (ref$ = table1).length; i$ < len$; ++i$) {
3. ref1$ = ref$[i$], id1 = ref1$.id, name = ref1$.name;
4. for (j$ = 0, len1$ = (ref1$ = table2).length; j$ < len1$; ++j$) {
5. ref2$ = ref1$[j$], id2 = ref2$.id, age = ref2$.age;
6. if (id1 === id2) {
7. ({
8. id: id1,
9. name: name,
10. age: age
11. });
12. }
13. }
14.}

你可以使用层叠来暗指所映射的那个值。

1.[.. + 1 for [1 2 3]] # => [2, 3, 4]
2.
3.list-of-obj =
4. * name: \Alice
5. age: 23
6. * name: \Betty
7. age: 26
8.
9.[..name for list-of-obj] # => ['Alice', 'Betty']

1.var i$, x$, ref$, len$, listOfObj, y$;
2.for (i$ = 0, len$ = (ref$ = [1, 2, 3]).length; i$ < len$; ++i$) {
3. x$ = ref$[i$];
4. x$ + 1;
5.}
6.listOfObj = [{
7. name: 'Alice',
8. age: 23
9.}, {
10. name: 'Betty',
11. age: 26
12.}];
13.for (i$ = 0, len$ = listOfObj.length; i$ < len$; ++i$) {
14. y$ = listOfObj[i$];
15. y$.name;
16.}

对象推导式产生对象:

1.{[key, val * 2] for key, value of {a: 1, b: 2}}
2.# => {a: 2, b: 4}

1.var key, ref$, value;
2.for (key in ref$ = {
3. a: 1,
4. b: 2
5.}) {
6. value = ref$[key];
7. [key, val * 2];
8.}

while循环:

1.i = 0
2.list = [1 to 10]
3.while n < 9
4. n = list[++i]

1.var i, list, n;
2.i = 0;
3.list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
4.while (n < 9) {
5. n = list[++i];
6.}

until等价于while not

while/until同样支持when,一个可选的else语句会自动在循环体根本不会执行后自动执行。

1.i = 0
2.list = [1 to 10]
3.while n < 9
4. n = list[++i]

1.var i, list, n;
2.i = 0;
3.list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
4.while (n < 9) {
5. n = list[++i];
6.}

do while循环:

1.i = 0
2.list = [1 to 10]
3.
4.do
5. i++
6.while list[i] < 9

1.var i, list;
2.i = 0;
3.list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
4.do {
5. i++;
6.} while (list[i] < 9);

while循环语句中支持更新:

1.i = 0
2.list = [1 to 10]
3.
4.while list[i] < 9, i++ then i

1.var i, list;
2.i = 0;
3.list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
4.for (; list[i] < 9; i++) {
5. i;
6.}

while true循环:

1.i = 0
2.loop
3. \ha
4. break if ++i > 20
5.
6.i = 0
7.for ever
8. \ha
9. if ++i > 20
10. break

1.var i;
2.i = 0;
3.for (;;) {
4. 'ha';
5. if (++i > 20) {
6. break;
7. }
8.}
9.i = 0;
10.for (;;) {
11. 'ha';
12. if (++i > 20) {
13. break;
14. }
15.}

Switch

break会被自动插入,允许多条件。

1.switch 6
2. case 1 then \hello
3. case 2, 4 then \boom
4. case 6
5. 'here it is'
6. default \something

1.switch (6) {
2. case 1:
3. 'hello';
4. break;
5. case 2:
6. case 4:
7. 'boom';
8. break;
9. case 6:
10. 'here it is';
11. break;
12. default:
13. 'something';
14.}

如果省略switch后的参数,那么默认是switch true。(翻译会等价的取反)

1.switch
2. case 5 == 6
3. \never
4. case false
5. 'also never'
6. case 6 / 2 is 3
7. \here

1.switch (false) {
2. case 5 !== 6:
3. 'never';
4. break;
5. case !false:
6. 'also never';
7. break;
8. case 6 / 2 !== 3:
9. 'here';
10.}

你可以使用fallthrough来取消自动插入breakfallthrough必须放到case块的最后,
当然switch也可以被用于表达式中。

1.result = switch 6
2. case 6
3. something = 5
4. fallthrough
5. case 4
6. 'this is it'
7.
8.result # => 'this is it'

1.var result, something;
2.result = (function() {
3. switch (6) {
4. case 6:
5. something = 5;
6. // fallthrough
7. case 4:
8. return 'this is it';
9. }
10.}());
11.result;

|case的语法糖,=>then的语法糖,| otherwise| _都是default的语法糖。

1.switch 'moto'
2.| "something" => \hello
3.| \explosion \boom => \boom
4.| <[ the moto ? ]> => 'here it is'
5.| otherwise => \something

1.switch ('moto') {
2. case "something":
3. 'hello';
4. break;
5. case 'explosion':
6. case 'boom':
7. 'boom';
8. break;
9. case 'the':
10. case 'moto':
11. case '?':
12. 'here it is';
13. break;
14. default:
15. 'something';
16.}

switch语句中可以使用that关键字:

1.switch num
2.| 2 => console.log that
3.| _ => console.log that

1.var that;
2.switch (that = num) {
3. case 2:
4. console.log(that);
5. break;
6. default:
7. console.log(that);
8.}

在箭头(如:->等),:=之后出现case,会形成隐式switch语句:

1.func = (param) ->
2. | param.length < 5 => param.length
3. | _ => param.slice 3
4.
5.func \hello # => lo
6.
7.state = | 2 + 2 is 5 => 'I love Big Brother'
8. | _ => 'I love Julia'

1.var func, state;
2.func = function(param) {
3. switch (false) {
4. case !(param.length < 5):
5. return param.length;
6. default:
7. return param.slice(3);
8. }
9.};
10.func('hello');
11.state = (function() {
12. switch (false) {
13. case 2 + 2 !== 5:
14. return 'I love Big Brother';
15. default:
16. return 'I love Julia';
17. }
18.}());

你也可以使用CoffeeScript那样风格的switch语句:

1.day = \Sun
2.switch day
3. when 'Mon' then 'go to work'
4. when 'Tue' then 'go to a movie'
5. when 'Thu' then 'go drinking'
6. when 'Fri','Sat'
7. 'go dancing'
8. when 'Sun' then 'drink more'
9. else 'go to work'

1.var day;
2.day = 'Sun';
3.switch (day) {
4. case 'Mon':
5. 'go to work';
6. break;
7. case 'Tue':
8. 'go to a movie';
9. break;
10. case 'Thu':
11. 'go drinking';
12. break;
13. case 'Fri':
14. case 'Sat':
15. 'go dancing';
16. break;
17. case 'Sun':
18. 'drink more';
19. break;
20. default:
21. 'go to work';
22.}