2014-09-26 11:11:06 +04:00
|
|
|
|
---
|
|
|
|
|
language: LiveScript
|
2017-08-25 11:34:41 +03:00
|
|
|
|
filename: learnLivescript-cn.ls
|
2014-09-26 11:11:06 +04:00
|
|
|
|
contributors:
|
|
|
|
|
- ["Christina Whyte", "http://github.com/kurisuwhyte/"]
|
2014-09-26 12:16:19 +04:00
|
|
|
|
translators:
|
|
|
|
|
- ["ShengDa Lyu", "http://github.com/SDLyu/"]
|
|
|
|
|
lang: zh-cn
|
2014-09-26 11:11:06 +04:00
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
LiveScript 是一种具有函数式特性且编译成 JavaScript 的语言,能对应 JavaScript 的基本语法。
|
2014-09-29 06:30:40 +04:00
|
|
|
|
还有些额外的特性如:柯里化,组合函数,模式匹配,还有借镜于 Haskell,F# 和 Scala 的许多特点。
|
2014-09-26 11:11:06 +04:00
|
|
|
|
|
|
|
|
|
LiveScript 诞生于 [Coco][],而 Coco 诞生于 [CoffeeScript][]。
|
|
|
|
|
LiveScript 目前已释出稳定版本,开发中的新版本将会加入更多特性。
|
|
|
|
|
|
|
|
|
|
[Coco]: http://satyr.github.io/coco/
|
|
|
|
|
[CoffeeScript]: http://coffeescript.org/
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
非常期待您的反馈,你可以通过
|
2014-09-26 11:11:06 +04:00
|
|
|
|
[@kurisuwhyte](https://twitter.com/kurisuwhyte) 与我连系 :)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```coffeescript
|
|
|
|
|
# 与 CoffeeScript 一样,LiveScript 使用 # 单行注解。
|
|
|
|
|
|
|
|
|
|
/*
|
2014-09-26 11:13:10 +04:00
|
|
|
|
多行注解与 C 相同。使用注解可以避免被当成 JavaScript 输出。
|
2014-09-26 11:11:06 +04:00
|
|
|
|
*/
|
|
|
|
|
```
|
|
|
|
|
```coffeescript
|
|
|
|
|
# 语法的部份,LiveScript 使用缩进取代 {} 来定义区块,
|
|
|
|
|
# 使用空白取代 () 来执行函数。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
########################################################################
|
|
|
|
|
## 1. 值类型
|
|
|
|
|
########################################################################
|
|
|
|
|
|
|
|
|
|
# `void` 取代 `undefined` 表示未定义的值
|
|
|
|
|
void # 与 `undefined` 等价但更安全(不会被覆写)
|
|
|
|
|
|
|
|
|
|
# 空值则表示成 Null。
|
|
|
|
|
null
|
|
|
|
|
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 最基本的值类型数据是罗辑类型:
|
2014-09-26 11:11:06 +04:00
|
|
|
|
true
|
|
|
|
|
false
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 罗辑类型的一些别名,等价于前者:
|
2014-09-26 11:11:06 +04:00
|
|
|
|
on; off
|
|
|
|
|
yes; no
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 数字与 JS 一样,使用倍精度浮点数表示。
|
|
|
|
|
10
|
|
|
|
|
0.4 # 开头的 0 是必要的
|
|
|
|
|
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 可以使用底线及单位后缀提高可读性,编译器会自动略过底线及单位后缀。
|
2014-09-26 11:11:06 +04:00
|
|
|
|
12_344km
|
|
|
|
|
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 字串与 JS 一样,是一种不可变的字元序列:
|
|
|
|
|
"Christina" # 单引号也可以!
|
2014-09-26 11:11:06 +04:00
|
|
|
|
"""Multi-line
|
|
|
|
|
strings
|
|
|
|
|
are
|
|
|
|
|
okay
|
|
|
|
|
too."""
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 在前面加上 \ 符号也可以表示字串:
|
2014-09-26 11:11:06 +04:00
|
|
|
|
\keyword # => 'keyword'
|
|
|
|
|
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 数组是值的有序集合。
|
2014-09-26 11:11:06 +04:00
|
|
|
|
fruits =
|
|
|
|
|
* \apple
|
|
|
|
|
* \orange
|
|
|
|
|
* \pear
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 可以用 [] 简洁地表示数组:
|
2014-09-26 11:11:06 +04:00
|
|
|
|
fruits = [ \apple, \orange, \pear ]
|
|
|
|
|
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 你可以更方便地建立字串数组,并使用空白区隔元素。
|
2014-09-26 11:11:06 +04:00
|
|
|
|
fruits = <[ apple orange pear ]>
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 以 0 为起始值的数组下标获取元素:
|
2014-09-26 11:11:06 +04:00
|
|
|
|
fruits[0] # => "apple"
|
|
|
|
|
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 对象是无序键值对集合(更多给节将在下面章节讨论)。
|
2014-09-26 11:11:06 +04:00
|
|
|
|
person =
|
|
|
|
|
name: "Christina"
|
|
|
|
|
likes:
|
|
|
|
|
* "kittens"
|
|
|
|
|
* "and other cute stuff"
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 你也可以用更简洁的方式表示对象:
|
2014-09-26 11:11:06 +04:00
|
|
|
|
person = {name: "Christina", likes: ["kittens", "and other cute stuff"]}
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 可以通过键值获取值:
|
2014-09-26 11:11:06 +04:00
|
|
|
|
person.name # => "Christina"
|
|
|
|
|
person["name"] # => "Christina"
|
|
|
|
|
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 正则表达式的使用跟 JavaScript 一样:
|
2014-09-26 11:11:06 +04:00
|
|
|
|
trailing-space = /\s$/ # dashed-words 变成 dashedWords
|
|
|
|
|
|
|
|
|
|
# 你也可以用多行描述表达式!(注解和空白会被忽略)
|
|
|
|
|
funRE = //
|
|
|
|
|
function\s+(.+) # name
|
|
|
|
|
\s* \((.*)\) \s* # arguments
|
|
|
|
|
{ (.*) } # body
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
########################################################################
|
|
|
|
|
## 2. 基本运算
|
|
|
|
|
########################################################################
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 数值操作符与 JavaScript 一样:
|
2014-09-26 11:11:06 +04:00
|
|
|
|
1 + 2 # => 3
|
|
|
|
|
2 - 1 # => 1
|
|
|
|
|
2 * 3 # => 6
|
|
|
|
|
4 / 2 # => 2
|
|
|
|
|
3 % 2 # => 1
|
|
|
|
|
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 比较操作符大部份也一样,除了 `==` 等价于 JS 中的 `===`,
|
2014-09-26 11:11:06 +04:00
|
|
|
|
# JS 中的 `==` 在 LiveScript 里等价于 `~=`,
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# `===` 能进行对象、数组和严格比较。
|
2014-09-26 11:11:06 +04:00
|
|
|
|
2 == 2 # => true
|
|
|
|
|
2 == "2" # => false
|
|
|
|
|
2 ~= "2" # => true
|
|
|
|
|
2 === "2" # => false
|
|
|
|
|
|
|
|
|
|
[1,2,3] == [1,2,3] # => false
|
|
|
|
|
[1,2,3] === [1,2,3] # => true
|
|
|
|
|
|
|
|
|
|
+0 == -0 # => true
|
|
|
|
|
+0 === -0 # => false
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 其它关系操作符包括 <、<=、> 和 >=
|
2014-09-26 11:11:06 +04:00
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 罗辑值可以通过 `or`、`and` 和 `not` 结合:
|
2014-09-26 11:11:06 +04:00
|
|
|
|
true and false # => false
|
|
|
|
|
false or true # => true
|
|
|
|
|
not false # => true
|
|
|
|
|
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 集合也有一些便利的操作符
|
2014-09-26 11:11:06 +04:00
|
|
|
|
[1, 2] ++ [3, 4] # => [1, 2, 3, 4]
|
|
|
|
|
'a' in <[ a b c ]> # => true
|
|
|
|
|
'name' of { name: 'Chris' } # => true
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
########################################################################
|
|
|
|
|
## 3. 函数
|
|
|
|
|
########################################################################
|
|
|
|
|
|
|
|
|
|
# 因为 LiveScript 是函数式特性的语言,你可以期待函数在语言里被高规格的对待。
|
|
|
|
|
add = (left, right) -> left + right
|
|
|
|
|
add 1, 2 # => 3
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 加上 ! 防止函数执行后的返回值
|
2014-09-26 11:11:06 +04:00
|
|
|
|
two = -> 2
|
|
|
|
|
two!
|
|
|
|
|
|
|
|
|
|
# LiveScript 与 JavaScript 一样使用函式作用域,且一样拥有闭包的特性。
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 与 JavaScript 不同的地方在于,`=` 变量赋值时,左边的对象永远不用变量宣告。
|
2014-09-26 11:11:06 +04:00
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# `:=` 操作符允许*重新賦值*父作用域里的变量。
|
2014-09-26 11:11:06 +04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 你可以解构函数的参数,从不定长度的参数结构里获取感兴趣的值。
|
|
|
|
|
tail = ([head, ...rest]) -> rest
|
|
|
|
|
tail [1, 2, 3] # => [2, 3]
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 你也可以使用一元或二元操作符转换参数。当然也可以预设传入的参数值。
|
2014-09-26 11:11:06 +04:00
|
|
|
|
foo = (a = 1, b = 2) -> a + b
|
|
|
|
|
foo! # => 3
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 你可以以拷贝的方式传入参数来避免副作用,例如:
|
2014-09-26 11:11:06 +04:00
|
|
|
|
copy = (^^target, source) ->
|
|
|
|
|
for k,v of source => target[k] = v
|
|
|
|
|
target
|
|
|
|
|
a = { a: 1 }
|
|
|
|
|
copy a, { b: 2 } # => { a: 1, b: 2 }
|
|
|
|
|
a # => { a: 1 }
|
|
|
|
|
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 使用长箭号取代短箭号来柯里化一个函数:
|
2014-09-26 11:11:06 +04:00
|
|
|
|
add = (left, right) --> left + right
|
|
|
|
|
add1 = add 1
|
|
|
|
|
add1 2 # => 3
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 函式里有一个隐式的 `it` 变量,意谓着你不用宣告它。
|
2014-09-26 11:11:06 +04:00
|
|
|
|
identity = -> it
|
|
|
|
|
identity 1 # => 1
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 操作符在 LiveScript 里不是一個函数,但你可以简单地将它们转换成函数!
|
|
|
|
|
# Enter the operator sectioning:
|
2014-09-26 11:11:06 +04:00
|
|
|
|
divide-by-2 = (/ 2)
|
|
|
|
|
[2, 4, 8, 16].map(divide-by-2) .reduce (+)
|
|
|
|
|
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# LiveScript 里不只有应用函数,如同其它良好的函数式语言,你可以合并函数获得更多发挥:
|
2014-09-26 11:11:06 +04:00
|
|
|
|
double-minus-one = (- 1) . (* 2)
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 除了普通的数学公式合并 `f . g` 之外,还有 `>>` 和 `<<` 操作符定义函数的合并顺序。
|
2014-09-26 11:11:06 +04:00
|
|
|
|
double-minus-one = (* 2) >> (- 1)
|
|
|
|
|
double-minus-one = (- 1) << (* 2)
|
|
|
|
|
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 说到合并函数的参数, LiveScript 使用 `|>` 和 `<|` 操作符将参数传入:
|
2014-09-26 11:11:06 +04:00
|
|
|
|
map = (f, xs) --> xs.map f
|
|
|
|
|
[1 2 3] |> map (* 2) # => [2 4 6]
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 你也可以选择填入值的位置,只需要使用底线 _ 标记:
|
2014-09-26 11:11:06 +04:00
|
|
|
|
reduce = (f, xs, initial) --> xs.reduce f, initial
|
|
|
|
|
[1 2 3] |> reduce (+), _, 0 # => 6
|
|
|
|
|
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 你也能使 _ 让任何函数变成偏函数应用:
|
2014-09-26 11:11:06 +04:00
|
|
|
|
div = (left, right) -> left / right
|
|
|
|
|
div-by-2 = div _, 2
|
|
|
|
|
div-by-2 4 # => 2
|
|
|
|
|
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 最后,也很重要的,LiveScript 拥有後呼叫特性, 可以是基於回调的代码
|
|
|
|
|
# (你可以试试其它函数式特性的解法,比如 Promises):
|
2014-09-26 11:11:06 +04:00
|
|
|
|
readFile = (name, f) -> f name
|
|
|
|
|
a <- readFile 'foo'
|
|
|
|
|
b <- readFile 'bar'
|
|
|
|
|
console.log a + b
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 等同於:
|
2014-09-26 11:11:06 +04:00
|
|
|
|
readFile 'foo', (a) -> readFile 'bar', (b) -> console.log a + b
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
########################################################################
|
|
|
|
|
## 4. 模式、判断和流程控制
|
|
|
|
|
########################################################################
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 流程控制可以使用 `if...else` 表达式:
|
2014-09-26 11:11:06 +04:00
|
|
|
|
x = if n > 0 then \positive else \negative
|
|
|
|
|
|
|
|
|
|
# 除了 `then` 你也可以使用 `=>`
|
|
|
|
|
x = if n > 0 => \positive
|
|
|
|
|
else \negative
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 过於复杂的流程可以用 `switch` 表达式代替:
|
2014-09-26 11:11:06 +04:00
|
|
|
|
y = {}
|
|
|
|
|
x = switch
|
|
|
|
|
| (typeof y) is \number => \number
|
|
|
|
|
| (typeof y) is \string => \string
|
|
|
|
|
| 'length' of y => \array
|
|
|
|
|
| otherwise => \object # `otherwise` 和 `_` 是等价的。
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 函数主体、宣告式和赋值式可以表式成 `switch`,这可以省去一些代码:
|
2014-09-26 11:11:06 +04:00
|
|
|
|
take = (n, [x, ...xs]) -->
|
|
|
|
|
| n == 0 => []
|
|
|
|
|
| _ => [x] ++ take (n - 1), xs
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
########################################################################
|
|
|
|
|
## 5. 推导式
|
|
|
|
|
########################################################################
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 在 JavaScript 的标准函式库里有一些辅助函数能帮助处理列表及对象
|
2014-09-26 11:11:06 +04:00
|
|
|
|
#(LiveScript 则带有一个 prelude.ls ,作为标准函式库的补充 ),
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 推导式能让你使用优雅的语法且快速地处理这些事:
|
2014-09-26 11:11:06 +04:00
|
|
|
|
oneToTwenty = [1 to 20]
|
|
|
|
|
evens = [x for x in oneToTwenty when x % 2 == 0]
|
|
|
|
|
|
|
|
|
|
# 在推导式里 `when` 和 `unless` 可以当成过滤器使用。
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 对象推导式在使用上也是同样的方式,差别在于你使用的是对象而不是数组:
|
2014-09-26 11:11:06 +04:00
|
|
|
|
copy = { [k, v] for k, v of source }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
########################################################################
|
|
|
|
|
## 6. OOP
|
|
|
|
|
########################################################################
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 虽然 LiveScript 是一门函数式语言,但具有一些命令式及面向对象的特性。
|
|
|
|
|
# 像是 class 语法和一些借镜於 CoffeeScript 的类别继承语法糖:
|
2014-09-26 11:11:06 +04:00
|
|
|
|
class Animal
|
|
|
|
|
(@name, kind) ->
|
|
|
|
|
@kind = kind
|
|
|
|
|
action: (what) -> "*#{@name} (a #{@kind}) #{what}*"
|
|
|
|
|
|
|
|
|
|
class Cat extends Animal
|
|
|
|
|
(@name) -> super @name, 'cat'
|
|
|
|
|
purr: -> @action 'purrs'
|
|
|
|
|
|
|
|
|
|
kitten = new Cat 'Mei'
|
|
|
|
|
kitten.purr! # => "*Mei (a cat) purrs*"
|
|
|
|
|
|
2014-09-29 06:30:40 +04:00
|
|
|
|
# 除了类别的单一继承模式之外,还提供了像混入 (Mixins) 这种特性。
|
|
|
|
|
# Mixins 在语言里被当成普通对象:
|
2014-09-26 11:11:06 +04:00
|
|
|
|
Huggable =
|
|
|
|
|
hug: -> @action 'is hugged'
|
|
|
|
|
|
|
|
|
|
class SnugglyCat extends Cat implements Huggable
|
|
|
|
|
|
|
|
|
|
kitten = new SnugglyCat 'Purr'
|
|
|
|
|
kitten.hug! # => "*Mei (a cat) is hugged*"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## 延伸阅读
|
|
|
|
|
|
|
|
|
|
LiveScript 还有许多强大之处,但这些应该足够启发你写些小型函数式程式了。
|
|
|
|
|
[LiveScript](http://livescript.net/)有更多关于 LiveScript 的资讯
|
2014-09-29 06:30:40 +04:00
|
|
|
|
和线上编译器等着你来试!
|
2014-09-26 11:11:06 +04:00
|
|
|
|
|
|
|
|
|
你也可以参考
|
|
|
|
|
[prelude.ls](http://gkz.github.io/prelude-ls/),和一些 `#livescript`
|
2014-09-29 06:30:40 +04:00
|
|
|
|
的网络聊天室频道。
|