- 文档
- 教程
【免费下载链接】learnxinyminutes-docs
Code documentation written as code! How novel and totally my idea!
本指南基于 learnxinyminutes-docs 仓库中的 es/livescript.md(其英语原版为仓库根目录的 livescript.md)整理成文。LiveScript 是一门编译到 JavaScript 的函数式语言,与宿主语言共享大部分底层语义,并额外带来柯里化、函数组合、模式匹配、推导式等大量借鉴自 Haskell、F# 与 Scala 的语言特性。读完本文,你将掌握 LiveScript 从基本值类型、运算体系、函数式核心(组合、管道、柯里化、back-call)到模式守卫、推导式与面向对象编程的完整实战能力,并了解如何在本仓库中定位各语言版本的教程原文与配套规范。
LiveScript 是什么:定位与语言谱系
按照 livescript.md 与 es/livescript.md 的说明,LiveScript 是一个函数式、编译到 JavaScript的语言:它输出标准的 JavaScript,因此可以无缝运行在既有 JS 生态中;同时它在语法层面引入缩进式块结构、空白分隔的函数调用(而非花括号与圆括号),让代码更简洁、更具表现力。
在谱系上,文档明确指出:
- LiveScript 是 [Coco] 的一个分支(fork);
- 而 Coco 本身又是 [CoffeeScript] 的一个分支。
因此 LiveScript 与 CoffeeScript 是"表亲"关系:单行注释同样使用#,语法同样依赖缩进。文档同时说明,LiveScript 语言本身已经稳定,且新版本仍在积极开发中,以引入更多特性。
仓库佐证:本文档在多语言目录中均有对应版本,除西班牙语版 es/livescript.md 外,还有中文版 zh-cn/livescript.md 与法语版 fr/livescript.md,各版本正文结构与代码示例保持一致,仅注释语言不同。
注释与语法约定:从 CoffeeScript 继承的表亲
LiveScript 的注释规则与 CoffeeScript 一脉相承:
# 单行注释使用井号,与 CoffeeScript 表亲完全一致 /* 多行注释使用 C 风格。 只有这种注释会在编译输出的 JavaScript 中保留。 */ # 就语法而言,LiveScript 用缩进界定代码块(而不是花括号 {}), # 用空白来应用函数(而不是圆括号)。需要特别注意:#单行注释在编译输出中会被丢弃,而/* ... */块注释会被保留到生成的 JavaScript 中——如果你希望注释随产物分发,请使用后者。
一、基本值类型
LiveScript 的基本值与 JavaScript 保持对齐,但做了若干"更安全、更严格"的调整:
空值与逻辑值
void # 等价于 `undefined`,但更安全(不可被覆写) null # 表示"没有合法值" true false # 逻辑值拥有一组等价别名: on; off yes; no文档特别强调:缺失值使用关键字void而非undefined表示,因为它无法被覆盖,语义更可靠。
数字
10 0.4 # 注意:开头的 0 是必需的 # 为便于阅读,可以在数字中使用下划线和字母后缀,编译器会忽略它们: 12_344km与 JS 一样,数字是双精度浮点数;12_344km中的下划线与km后缀仅用于可读性,编译后会被剔除。
字符串与关键字
"Christina" # 单引号也可以! """多行 字符串 同样 支持。""" # 想编码一个关键字时,使用反斜杠即可: \keyword # => 'keyword'字符串是不可变的字符序列;\keyword的写法可以快速生成一个带引号的字符串字面量(编译结果即'keyword')。
数组与对象
数组是有序集合,LiveScript 提供三种等价写法:
# 方式一:缩进 + 星号列表 frutas = * \manzana * \naranja * \pera # 方式二:方括号 frutas = [ \manzana, \naranja, \pera ] # 方式三:尖括号 + 空白分隔(专门用于字符串列表,最简洁) frutas = <[ manzana naranja pera ]> # 按下标取值(从 0 开始): frutas[0] # => "manzana"对象是无序的键/值对集合,同样有两种写法:
persona = nombre: "Christina" gusta: * "gatitos" * "otras cosas" # 更紧凑的写法: persona = {nombre: "Christina", gusta: ["gatitos", "otras cosas"]} # 按键取值: persona.nombre # => "Christina" persona["nombre"] # => "Christina"正则表达式
正则的语法与 JavaScript 相同,但额外支持多行正则(注释与空白会被忽略):
expresion-regular = /\s$/ # 多行表达式(注释与空白会被忽略): expresion-regular = // function\s+(.+) # 名称 \s* \((.*)\) \s* # 参数 { (.*) } # 函数体 //二、基本运算
算术运算
与 JavaScript 完全一致:
1 + 2 # => 3 2 - 1 # => 1 2 * 3 # => 6 4 / 2 # => 2 3 % 2 # => 1比较运算:==、~=、===的三层语义
这是 LiveScript 最值得注意的差异点,文档用一组对照例子讲得很清楚:
==等价于 JS 的===(严格相等,不做类型转换);- JS 原来的宽松相等
==在 LiveScript 中写作~=; ===则更进一步,支持对象与数组的深度比较,并执行更严格的比较。
2 == 2 # => true 2 == "2" # => false (不做类型转换) 2 ~= "2" # => true (宽松比较,等价 JS 的 ==) 2 === "2" # => false [1,2,3] == [1,2,3] # => false (引用比较) [1,2,3] === [1,2,3] # => true (深度比较) +0 == -0 # => true +0 === -0 # => false (更严格的比较能区分 +0 与 -0)其余关系运算符<、<=、>、>=与 JS 相同。
逻辑运算
逻辑值通过关键字or、and、not组合:
true and false # => false false or true # => true not false # => true集合专属运算符
LiveScript 为集合增加了三个便捷运算符:
[1, 2] ++ [3, 4] # => [1, 2, 3, 4] (数组拼接) 'a' in <[ a b c ]> # => true (元素属于数组) 'nombre' of { nombre: 'Chris' } # => true (键属于对象)三、函数:一等公民的完整待遇
作为函数式语言,LiveScript 对函数给予了最高规格的支持。
定义、调用与无参调用
# 函数是一等公民: suma = (primerElemento, segundoElemento) -> primerElemento + segundoElemento suma 1, 2 # => 3 (调用用空白,无需括号) # 无参函数用感叹号快速调用: dos = -> 2 dos!作用域:=与:=
LiveScript 与 JavaScript 一样采用函数作用域并支持闭包。但区别在于:=是声明运算符,总会声明左侧变量;若想复用父作用域中的名字,则必须显式使用:=。这一设计避免了 JS 中常见的隐式全局变量陷阱。
参数解构
函数参数可以直接解构复杂数据结构:
cola = ([cabeza, ...resto]) -> resto cola [1, 2, 3] # => [2, 3]默认参数与参数克隆
参数支持默认值,也支持用^^前缀克隆传入对象以规避副作用:
foo = (a = 1, b = 2) -> a + b foo! # => 3 # ^^ 克隆一个参数,避免修改原对象: copiar = (^^objetivo, fuente) -> for k,v of fuente => objetivo[k] = v objetivo a = { a: 1 } copiar a, { b: 2 } # => { a: 1, b: 2 } a # => { a: 1 } (原对象未被修改)柯里化:长箭头-->
短箭头->定义普通函数,长箭头-->定义可柯里化函数——部分应用后返回新函数:
suma = (primerElemento, segundoElemento) --> primerElemento + segundoElemento sumaAbreviada = suma 1 sumaAbreviada 2 # => 3隐式参数it
未声明任何参数的函数会获得一个隐式参数it:
identidad = -> it identidad 1 # => 1运算符切片:把运算符变成函数
运算符在 LiveScript 中不是函数,但可以通过**切片(sectioning)**轻松转成函数:
dividir-entre-2 = (/ 2) [2, 4, 8, 16].map(dividir-entre-2) .reduce (+)函数组合:.、>>、<<
函数式语言必备的组合能力,LiveScript 提供三种风格:
# 经典数学记法 f . g: doble-menos-uno = (- 1) . (* 2) # >> 描述从左到右的数值流: doble-menos-uno = (* 2) >> (- 1) # << 描述从右到左的数值流(等价写法): doble-menos-uno = (- 1) << (* 2)管道:|>与<|
管道运算符把值送入函数,用下划线_标记值的插入位置:
map = (f, xs) --> xs.map f [1 2 3] |> map (* 2) # => [2 4 6] # 用 _ 指定值的位置: reducir = (f, xs, initial) --> xs.reducir f, initial [1 2 3] |> reducir (+), _, 0 # => 6部分应用:下划线占位
下划线同样用于常规的部分应用,可作用于任意函数:
division = (dividendo, divisor) -> dividendo / divisor dividir-entre-2 = division _, 2 dividir-entre-2 4 # => 2Back-calls:扁平化的回调
LiveScript 提供 back-calls 机制,把嵌套回调改写为顺序写法(文档同时建议:能使用 Promise 等更函数式方案时应优先使用):
leerArchivo = (nombre, f) -> f nombre a <- leerArchivo 'foo' b <- leerArchivo 'bar' console.log a + b # 等价于传统嵌套写法: leerArchivo 'foo', (a) -> leerArchivo 'bar', (b) -> console.log a + b四、模式、守卫与控制流
if...else 表达式
条件分支本身是表达式,可以直接赋值:
x = if n > 0 then \positive else \negative # 也可以用 => 代替 then: x = if n > 0 => \positivo else \negativoswitch 表达式
复杂条件更适合用 switch 表达,分支用|引入,otherwise与_都表示"始终匹配":
y = {} x = switch | (typeof y) is \number => \numero | (typeof y) is \string => \string | 'length' of y => \arreglo | otherwise => \objeto # `otherwise` 和 `_` 等价隐式 switch
函数体、声明与赋值自带一个隐式 switch,无需再写switch关键字——这是 LiveScript 用守卫(guard)做递归的经典写法:
take = (n, [x, ...xs]) --> | n == 0 => [] | _ => [x] ++ take (n - 1), xs五、Comprehensions(推导式)
处理列表与对象时,除了 JavaScript 标准库(以及 LiveScript 的"标准库" prelude-ls)提供的函数式辅助工具,推导式通常写起来更快、语法更直观:
unoAVeinte = [1 to 20] pares = [x for x in unoAVeinte when x % 2 == 0] # `when` 与 `unless` 都可以作为推导式中的过滤器。 # 对象推导式同理,只是返回对象而非数组: copiar = { [k, v] for k, v of source }六、面向对象编程:类、继承与 Mixin
LiveScript 在函数式内核之上,也提供了从 CoffeeScript 继承而来的类语法糖:
class Animal (@nombre, tipo) -> @tipo = tipo action: (accion) -> "*#{@nombre} (un #{@tipo}) #{accion}*" class Gato extends Animal (@nombre) -> super @nombre, 'gato' ronronear: -> @action 'ronronea' gatito = new Gato 'Mei' gatito.ronronear! # => "*Mei (un gato) ronronea*"(@nombre, tipo) ->是 CoffeeScript 风格的构造器写法,@前缀自动把参数赋给实例属性;extends实现单继承,super调用父类构造器;- 方法调用同样可以用
!快速执行。
除了经典单继承,还可以用implements混入任意多个 mixin——mixin 只是普通对象:
Abrazable = abrazar: -> @action 'es abrazado' class GatoAbrazable extends Gato implements Abrazable gatito = new GatoAbrazable 'Ronroneo' gatito.abrazar! # => "*Ronroneo (un gato) es abrazado*"更多资源与本仓库的配套信息
LiveScript 远不止本文这些内容,但以上已足够支撑你开始编写函数式的小型应用:
- 官方站点提供大量语言文档与在线编译器,便于即时试玩;
- 建议搭配 prelude-ls(LiveScript 的"标准库",涵盖列表/对象处理的函数式工具)一起使用。
就本仓库而言,若你想继续深入:
- 本文档的英语原版位于 livescript.md,是内容最完整、更新最及时的版本;
- 中文版见 zh-cn/livescript.md,法语版见 fr/livescript.md;
- 仓库对所有教程文档统一管理:文档头部 YAML frontmatter 的合法字段(
name、category、filename、contributors、translators等)由 lint/frontmatter.py 校验,写作与翻译规范详见 CONTRIBUTING.md;本指南对应的西班牙语版头部即记录了原作者 Christina Whyte 与译者 Daniel Zendejas 的署名信息; - 整个仓库的定位见 README.md:用"可运行的、带注释的代码"来讲解编程语言,即"X 分钟学会 Y"。
- 文档
- 教程
【免费下载链接】learnxinyminutes-docs
Code documentation written as code! How novel and totally my idea!
相关推荐
Learn X in Y minutes 之 JavaScript:基于 cs/javascript.md 的语言核心完整实战指南
Learn X in Y minutes 之 JavaScript:基于 cs/javascript.md 的语言核心完整实战指南 本文以 learnxinym
文档教程Learn X in Y Minutes 系列:HTML5 标记语言入门指南(基于 el/html.md 希腊语译文)
Learn X in Y Minutes 系列:HTML5 标记语言入门指南(基于 el/html.md 希腊语译文) 本篇指南源自 learnxinyminu
文档教程Learn X in Y Minutes 系列:Groovy 动态语言完整实战入门——集合、闭包与元编程(基于 learnxinyminutes-docs)
Learn X in Y Minutes 系列:Groovy 动态语言完整实战入门——集合、闭包与元编程(基于 learnxinyminutes docs) 本
文档教程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考