LiveScript 是一种编译成 JavaScript 的语言。它与 JavaScript 具有直接的映射关系,并允许您编写简洁的代码,避免重复的样板代码。虽然 LiveScript 添加了许多功能来辅助函数式编程,但它也对面向对象和命令式编程进行了许多改进。
LiveScript 是 Coco 的分支,并且是 CoffeeScript 的间接后代,它与 CoffeeScript 具有很强的兼容性。
npm install -g livescript
关注 @gkzahariev 以获取 LiveScript 的更新。
特色博文:LiveScript 1.4.0 - 源映射及更多!
双击示例将其加载到编译器/REPL 中。法语文档:Français。
# Easy listing of implicit objects
table1 =
* id: 1
name: 'george'
* id: 2
name: 'mike'
* id: 3
name: 'donald'
table2 =
* id: 2
age: 21
* id: 1
age: 20
* id: 3
age: 26
# Implicit access, accessignment
up-case-name = (.name .= to-upper-case!)
# List comprehensions, destructuring, piping
[{id:id1, name, age} for {id:id1, name} in table1
for {id:id2, age} in table2
when id1 is id2]
|> sort-by (.id) # using 'sort-by' from prelude.ls
|> each up-case-name # using 'each' from prelude.ls
|> JSON.stringify
#=>
#[{"id":1,"name":"GEORGE","age":20},
# {"id":2,"name":"MIKE", "age":21},
# {"id":3,"name":"DONALD","age":26}]
# operators as functions, piping
map (.age), table2 |> fold1 (+)
#=> 67 ('fold1' and 'map' from prelude.ls)
var table1, table2, upCaseName, id1, name, id2, age;
table1 = [
{
id: 1,
name: 'george'
}, {
id: 2,
name: 'mike'
}, {
id: 3,
name: 'donald'
}
];
table2 = [
{
id: 2,
age: 21
}, {
id: 1,
age: 20
}, {
id: 3,
age: 26
}
];
upCaseName = function(it){
return it.name = it.name.toUpperCase();
};
JSON.stringify(
each(upCaseName)(
sortBy(function(it){
return it.id;
})(
(function(){
var i$, ref$, len$, ref1$, j$, len1$, ref2$, results$ = [];
for (i$ = 0, len$ = (ref$ = table1).length; i$ < len$; ++i$) {
ref1$ = ref$[i$], id1 = ref1$.id, name = ref1$.name;
for (j$ = 0, len1$ = (ref1$ = table2).length; j$ < len1$; ++j$) {
ref2$ = ref1$[j$], id2 = ref2$.id, age = ref2$.age;
if (id1 === id2) {
results$.push({
id: id1,
name: name,
age: age
});
}
}
}
return results$;
}()))));
fold1(curry$(function(x$, y$){
return x$ + y$;
}))(
map(function(it){
return it.age;
}, table2));
function curry$(f, bound){
var context,
_curry = function(args) {
return f.length > 1 ? function(){
var params = args ? args.concat() : [];
context = bound ? context || this : this;
return params.push.apply(params, arguments) <
f.length && arguments.length ?
_curry.call(context, params) : f.apply(context, params);
} : f;
};
return _curry();
}
无嵌套回调和无括号链式调用
<- $ 'h1' .on 'click' alert 'boom!'
$('h1').on('click', function(){
return alert('boom!');
});
您可以通过 npm 安装 LiveScript:sudo npm install -g livescript。
或者,您也可以下载它(zip,tar.gz),进入其目录,然后运行 sudo make install。使用 git 下载:git clone git://github.com/gkz/LiveScript.git && cd LiveScript && sudo make install。Node.js 需要安装在您的系统上。
您也可以通过在 LiveScript/browser/livescript.js 中包含文件并通过脚本标签将其包含在浏览器中直接使用它。然后,您必须调用 require("livescript").go()。如果您使用此方法,则您的 LiveScript 脚本必须放在包含的 livescript.js 文件之后,并且脚本标签必须具有 type="text/ls" 属性。
例如
<script src="livescript.js"></script>
<script type="text/ls">
console.log "boom #{window.location}"
</script>
<script>
var LiveScript = require("livescript");
LiveScript.go();
</script>
用法:lsc [options]... [file]...
不带任何选项使用 lsc 启动 REPL。
Usage: lsc [option]... [file]...
Use 'lsc' with no options to start REPL.
Misc:
-v, --version display version
-h, --help display this help message
-c, --compile compile to JavaScript and save as .js files
-e, --eval code::String pass as string from the command line as input
-d, --prelude automatically import prelude.ls in REPL
-r, --require paths::[String] require libraries before executing
-s, --stdin read stdin
-j, --json print/compile as JSON
-n, --nodejs pass options after this through to the 'node' binary
-w, --watch watch scripts for changes, and repeat
-k, --const compile all variables as constants
Output control:
-o, --output path::String compile into the specified directory
-p, --print print the result to stdout
-b, --bare compile without the top-level function wrapper
--no-header do not add "Generated by" header
-l, --lex print the tokens the lexer produces
-t, --tokens print the tokens the rewriter produces
-a, --ast print the syntax tree the parser produces
--debug print debug output when compiling
-m, --map String generate source maps - either: 'none', 'linked',
'linked-src', 'embedded', or 'debug'
--no-warn suppress compiler warnings
Version 1.6.0
<https://livescript.node.org.cn/>
lsc file.ls - 您可以省略 .ls。file.js:lsc -c file.lslsc -wc file.lslsc -co output srclsc -wco output srclsc -bpe '[1 to 5]'lsc - 使用 Ctrl-D 退出,使用 Ctrl-J 进行多行输入。您可以通过使用 .json.ls 文件扩展名或通过传入 -j,--json 标志来编译 LiveScript 样式的 JSON 到 .json 文件。
您可以将 -e,--eval 与 JSON 数据结合使用,以实现函数式命令行 JSON 处理。您提供的 JSON 数据在 eval 表达式中绑定到 this。您可以将 JSON 数据通过管道输入,并使用 -j,--json 标志,或者使用扩展名为 .json 的文件。
$ lsc -e '@name' package.json "livescript" $ cat package.json | lsc -je '@name' "livescript"
您可以使用 -d,--prelude 标志包含 prelude.ls。
$ lsc -de '@files |> map (.to-upper-case!)' package.json [ "LIB", "BIN", "README.MD", "LICENSE" ]
您也可以轻松地使用 -r,--require 标志引入模块。
lsc -r 'path' -de '@files |> map -> [it, path.resolve it]' package.json
[
[
"lib",
"/home/z/open-source/LiveScript/lib"
],
[
"bin",
"/home/z/open-source/LiveScript/bin"
],
[
"README.md",
"/home/z/open-source/LiveScript/README.md"
],
[
"LICENSE",
"/home/z/open-source/LiveScript/LICENSE"
]
]
使用 var LiveScript = require('livescript'); 或 require! livescript 将其引入您的 Node 或 Browserify 项目,或使用上述步骤进行浏览器安装。在 Node 中,引入此模块也会将其注册到 require.extensions 中。
LiveScript.compile(code :: String, options :: Object?) -> String
将 LiveScript 代码字符串编译成纯 JavaScript。如果字符串编译失败,则会抛出 SyntaxError。
选项
| bare :: Boolean = false | 如果为 true,则不使用顶级函数包装器进行编译 |
| header :: Boolean = true | 如果为 true,则添加“Generated by”标头 |
| const :: Boolean = false | 如果为 true,则将所有变量编译为常量 |
| json :: Boolean = false | 如果为 true,则编译为 JSON 而不是 JavaScript |
| warn :: Boolean = true | 如果为 false,则抑制编译器警告 |
| filename :: String? | 用于编译错误的可选文件名 |
LiveScript.run(code :: String, options :: Object?) -> String
评估 LiveScript 代码字符串。如果字符串编译失败,则会抛出 SyntaxError。请注意,这使用 Function 构造函数。
选项
| const :: Boolean = false | 如果为 true,则将所有变量编译为常量 |
| filename :: String? | 用于错误的可选文件名 |
LiveScript.ast(code :: String|Array) -> Object
生成 LiveScript 源代码的 AST 表示形式,如果它是字符串,则生成令牌流,如果它是数组,则生成令牌流。如果它是一个无法解析为 LiveScript 代码的字符串,则会抛出 SyntaxError。如果它是一个数组,如果流无效,则会抛出 Error。
LiveScript.tokens(code :: String, options :: Object?) -> Array
从 LiveScript 代码生成令牌流。请注意,这不会在调用之间保持状态。
选项
| raw :: Boolean = false | 如果为 true,则在标记化之前不刷新令牌流 - 建议保持默认值 |
| line :: Number = 0 | 令牌流的起始行号 |
LiveScript.lex(code :: String)
等价于 LiveScript.tokens(code, {raw: true})。
LiveScript.ast.* :: Object...
用于 LiveScript.ast() 的所有 AST 构造函数。
LiveScript.stab(code :: String, callback :: (err :: Error?) -> void, filename :: String?) -> void
运行代码字符串,并使用可选错误进行回调。
LiveScript.load(url :: String, callback :: (err :: Error?) -> void) -> void
通过 XMLHttpRequest 加载 url 处的远程 LiveScript 文件,并使用可选错误进行回调。
LiveScript.go() -> void
加载所有具有 type 属性为 "text/ls" 或 "application/ls" 的脚本。
将您自己的项目/公司添加到列表中!
prelude.ls 是使用 LiveScript 时推荐的基本库。它允许您执行以下操作
[1 2 3] |> map (* 2) |> filter (> 3) |> fold1 (+) #=> 10
您可以使用 -d 或 --prelude 选项自动将 prelude.ls 导入到 REPL 中。
Prelude 在此页面上加载,您可以在右侧的编译器/REPL 中运行内容时使用它。
编译时使用 -m, --map 选项生成源映射。它有几个可能的值,none - 默认值,linked,linked-src,embedded 和 debug
生成源映射时涉及三个文件
a 可以选择性地嵌入到 b 中,b 可以选择性地嵌入到 c 中,通过注释。
linked:不嵌入,c 通过相对路径链接到 b,b 也链接到 a
linked-src:b 嵌入到 c 中,但 a 链接到
embedded:所有内容都嵌入到 c 中
debug:与 linked 相同,但也会将源节点树的可读表示形式(类似于 ast 选项的输出)输出到 '.map.debug' 文件中。
如果您直接将 lsc 的输出提供给浏览器(即不进行进一步处理),请使用 linked 或 linked-src。它们使原始源代码保持分离,因此 JavaScript 文件仍然很小。linked-src 只是意味着您需要携带的文件更少,但代价是增加了 JavaScript 文件的大小。
对于其他所有情况,请使用 embedded - 它自包含,并且是大多数其他工具(如 browserify)作为输入接受的唯一形式。文件将明显变大,但您可以在构建管道的末尾运行一个单独的工具,将输出拆分回 linked 形式。
像许多现代语言一样,块由空格缩进分隔,换行符用于代替分号终止语句(如果要在一行上放置多个语句,您仍然可以使用分号)。
例如(左侧为 LiveScript,右侧为编译后的 JavaScript)
if 2 + 2 == 4 do-something()
if (2 + 2 === 4) {
doSomething();
}
您可以使用右侧的 LiveScript 编译器/REPL 自己尝试所有这些示例。
为了进一步澄清,在调用函数时可以省略括号。
add 2, 3
add(2, 3);
并且注释是
# from here to the end of the line.
// from here to the end of the line.
Lisp 黑客们,您可能会高兴地知道,您可以在变量和函数的名称中使用连字符。这些名称等价于驼峰命名法,并编译成驼峰命名法。例如 my-value = 42 == myValue = 42。
LiveScript 的文件扩展名为 .ls。
在 LiveScript 中定义函数非常轻量级
(x, y) -> x + y -> # an empty function times = (x, y) -> x * y # multiple lines, and be assigned to # a var like in JavaScript
var times;
(function(x, y){
return x + y;
});
(function(){});
times = function(x, y){
return x * y;
};
如您所见,函数定义相当简短!您可能还注意到我们省略了 return。在 LiveScript 中,几乎所有内容都是表达式,并且自动返回最后一个表达式。但是,如果您愿意,您仍然可以使用 return 强制返回,并且可以在箭头之前添加一个感叹号 ! 来抑制自动返回 no-ret = (x) !-> ...。
基本赋值与您预期的一样,variable = value,并且不需要变量声明。但是,与 CoffeeScript 不同,您必须使用 := 来修改上层作用域中的变量。
x = 10 do -> x = 5 x #=> 10 do -> x := 2 x #=> 2
var x;
x = 10;
(function(){
var x;
return x = 5;
})();
x;
(function(){
return x = 2;
})();
x;
几乎所有内容都是表达式,这意味着您可以执行以下操作
x = if 2 + 2 == 4
then 10
else 0
x #=> 10
var x; x = 2 + 2 === 4 ? 10 : 0; x;
诸如循环、switch 语句,甚至 try/catch 语句都是表达式。
如果只想声明一个变量而不初始化它,可以使用 var。
var x
var x;
您也可以使用const在LiveScript中声明常量。它们在编译时进行检查 - 编译后的JS没有区别。
尝试编译以下内容
const x = 10 x = 0
导致在第 2 行重新声明常量“x”。
但是,如果将对象声明为常量,则不会冻结它们 - 您仍然可以修改其属性。如果使用-k或--const标志进行编译,则可以强制所有变量都为常量。
有关与CoffeeScript的区别,请参阅CoffeeScript到LiveScript转换指南。
您可以双击任何示例将LiveScript代码加载到右侧的编译器中,或者您可以随意尝试自己的代码。按运行以执行编译后的JavaScript。请注意,LiveScript将编译后的JS包装在一个安全包装器(function(){...contents...}).call(this);中 - 为简洁起见,所有示例和此页面的编译器输出中都省略了此包装器。
.4无效,必须以零开头,例如0.4。
42 17.34 0.4
42; 17.34; 0.4;
下划线和附加的字母将被忽略。
64_000km
64000;
可以使用~使用2到36之间的任何基数。
6~12 2~1000 16~ff
8; 8; 255;
与CoffeeScript中的别名相同。
true false on off yes no
true; false; true; false; true; false;
在JavaScript中,可以重新定义undefined,因此谨慎使用始终产生未定义值的void运算符。
顶级void(不用作表达式)编译为空(用作占位符) - 必须将其用作要编译的值。
void x = void null
var x; // void compiles to nothing here! x = void 8; null;
您可以使用双引号或单引号。
'a string' "a string"
'a string'; "a string";
字符串可以用反斜杠而不是引号编写。反斜杠字符串不能包含, ; ] ) }或空格。
\word
func \word, \word;
(func \word)
[\word]
{prop:\word}
'word';
func('word', 'word');
func('word');
['word'];
({
prop: 'word'
});
双引号字符串允许插值。单引号字符串按原样传递。简单的变量可以在没有花括号的情况下进行插值。
"The answer is #{2 + 2}"
'As #{is}'
variable = "world"
"Hello #variable"
var variable;
"The answer is " + (2 + 2);
'As #{is}';
variable = "world";
"Hello " + variable;
在您的插值字符串前面加上%将返回原始部分作为数组。这允许您根据需要连接结果。
%"#x #y"
[x, " ", y];
多行字符串(也可以用双引号执行相同操作,以便与插值一起使用)
multiline = 'string can be multiline \
and go on and on \
beginning whitespace is \
ignored'
heredoc = '''
string can be multiline
with newlines
and go on and on
beginning whitespace is
ignored
'''
nospaces = 'deadbeef
deadbeef'
var multiline, heredoc, nospaces; multiline = 'string can be multiline and go on and on beginning whitespace is ignored'; heredoc = 'string can be multiline\nwith newlines\nand go on and on\nbeginning whitespace is\nignored'; nospaces = 'deadbeefdeadbeef';
单行注释以#开头。它们不会传递到编译后的输出中。
# single line comment
多行注释保留在输出中。
/* multiline comments use this format and are preserved in the output unlike single line ones */
/* multiline comments use this format and are preserved in the output unlike single line ones */
花括号是可选的
obj = {prop: 1, thing: 'moo'}
person =
age: 23
eye-color: 'green'
height: 180cm
oneline = color: 'blue', heat: 4
var obj, person, oneline;
obj = {
prop: 1,
thing: 'moo'
};
person = {
age: 23,
eyeColor: 'green',
height: 180
};
oneline = {
color: 'blue',
heat: 4
};
动态键
obj = "#variable": 234 (person.eye-color): false
var obj, ref$;
obj = (ref$ = {}, ref$[variable + ""] = 234, ref$[person.eyeColor] = false, ref$);
属性设置简写 - 如果希望属性名称与变量名称相同,则可以轻松地使用变量设置属性。
x = 1
y = 2
obj = {x, y}
var x, y, obj;
x = 1;
y = 2;
obj = {
x: x,
y: y
};
标记简写 - 轻松设置布尔属性。
{+debug, -live}
({
debug: true,
live: false
});
This - 无需使用点.来访问属性。
this @ @location
this; this; this.location;
使用单个/分隔的常规正则表达式。
/moo/gi
/moo/gi;
用//分隔 - 多行、注释、空格!
// | [!=]==? # equality | @@ # constructor | <\[(?:[\s\S]*?\]>)? # words //g
/|[!=]==?|@@|<\[(?:[\s\S]*?\]>)?/g;
用括号分隔的常规列表文字
[1, person.age, 'French Fries']
[1, person.age, 'French Fries'];
如果前面的项目不可调用,则不需要逗号
[1 2 3 true void \word 'hello there']
[1, 2, 3, true, void 8, 'word', 'hello there'];
使用缩进块创建隐式列表。它们至少需要两个项目才能工作。如果您只有一个项目,则可以添加一个yaddayaddayadda...来强制使用隐式列表。
my-list = 32 + 1 person.height 'beautiful' one-item = 1 ...
var myList, oneItem; myList = [32 + 1, person.height, 'beautiful']; oneItem = [1];
在隐式列出时,可以使用星号*来消除诸如隐式对象和隐式列表之类的隐式结构的歧义。星号不表示列表的项目,而仅仅是设置一个隐式结构,以便它不会与正在列出的其他结构混淆。
tree =
* 1
* 2
3
4
* 5
6
* 7
8
* 9
10
11
obj-list =
* name: 'tessa'
age: 23
* name: 'kendall'
age: 19
obj =
* name: 'tessa'
age: 23
obj-one-list =
* name: 'tessa'
age: 23
...
var tree, objList, obj, objOneList;
tree = [[1, [2, 3], 4], [5, 6, [7, 8, [9, 10]], 11]];
objList = [
{
name: 'tessa',
age: 23
}, {
name: 'kendall',
age: 19
}
];
obj = {
name: 'tessa',
age: 23
};
objOneList = [{
name: 'tessa',
age: 23
}];
单词列表
<[ list of words ]>
['list', 'of', 'words'];
to表示直到且包括该数字。til表示直到但不包括该数字。
您可以选择添加一个by,它定义范围的步长。
如果您省略第一个数字,则假定为0。
使用数字/字符串文字
[1 to 5] #=> [1, 2, 3, 4, 5] [1 til 5] #=> [1, 2, 3, 4] [1 to 10 by 2] #=> [1, 3, 7, 9] [4 to 1] #=> [4, 3, 2, 1] [to 5] #=> [0, 1, 2, 3, 4, 5] [\A to \D] #=> ['A', 'B', 'C', D']
[1, 2, 3, 4, 5]; [1, 2, 3, 4]; [1, 3, 5, 7, 9]; [4, 3, 2, 1]; [0, 1, 2, 3, 4, 5]; ["A", "B", "C", "D"];
使用任何表达式 - 如果您的范围使用表达式,并且希望它向下(即从较大的数字到较小的数字),则必须显式设置by -1。
x = 4 [1 to x] #=> [1, 2, 3, 4] [x to 0 by -1] #=> [4, 3, 2, 1, 0]
var x, i$;
x = 4;
for (i$ = 1; i$ <= x; ++i$) {
i$;
}
for (i$ = x; i$ >= 0; --i$) {
i$;
}
标签(对嵌套循环很有用)
:label 4 + 2
label: {
4 + 2;
}
constructor简写。
@@ @@x x@@y
constructor; constructor.x; x.constructor.y;
Yaddayaddayadda - 一个占位符
...
throw Error('unimplemented');
标准数学运算符
1 + 2 #=> 3 3 - 4 #=> -1 6 * 2 #=> 12 8 / 4 #=> 2
1 + 2; 3 - 4; 6 * 2; 8 / 4;
有一个余数运算符,就像在JavaScript中一样 - 但我们还添加了一个正确的模运算符。
-3 % 4 #=> -3 -3 %% 4 #=> 1
var ref$; -3 % 4; ((-3) % (ref$ = 4) + ref$) % ref$;
幂是右结合的,并且优先级高于一元运算符。^是**的别名
2 ** 4 #=> 16 3 ^ 4 #=> 81 -2 ^ 2 ^ 3 #=> -256
Math.pow(2, 4); Math.pow(3, 4); -Math.pow(2, Math.pow(2, 3));
增量和减量
n = 0 n++ #=> 0 ++n #=> 2 n-- #=> 2 --n #=> 0 x = n++ #=> 0 x #=> 0 n #=> 1 x = ++n #=> 2 x #=> 2 n #=> 2
var n, x; n = 0; n++; ++n; n--; --n; x = n++; x; n; x = ++n; x; n;
按位和移位运算符
14 .&. 9 #=> 8 14 .|. 9 #=> 15 14 .^. 9 #=> 7 ~9 #=> -10 9 .<<. 2 #=> 36 -9 .>>. 2 #=> -3 -9 .>>>. 2 #=> 1073741821
14 & 9; 14 | 9; 14 ^ 9; ~9; 9 << 2; -9 >> 2; -9 >>> 2;
转换为数字
+'4' #=> 4 -'3' #=> -3
+'4'; -'3';
严格相等(无类型强制)
2 + 4 == 6 #=> true \boom is 'boom' #=> true \boom != null #=> true 2 + 2 is not 4 #=> false 0 + 1 isnt 1 #=> false
2 + 4 === 6; 'boom' === 'boom'; 'boom' !== null; 2 + 2 !== 4; 0 + 1 !== 1;
模糊相等(带类型强制)
2 ~= '2' #=> true \1 !~= 1 #=> false
2 == '2'; '1' != 1;
大于/小于
2 < 4 #=> true 9 > 7 #=> true 8 <= 8 #=> true 7 >= 8 #=> false
2 < 4; 9 > 7; 8 <= 8; 7 >= 8;
链式比较
1 < 2 < 4 #=> true 1 < 2 == 4/2 > 0 #=> true
var ref$; 1 < 2 && 2 < 4; 1 < 2 && 2 === (ref$ = 4 / 2) && ref$ > 0;
最小值/最大值 - 返回两个操作数中较小/较大的一个。
4 >? 8 #=> 8 9 - 5 <? 6 #=> 4
var ref$; 4 > 8 ? 4 : 8; (ref$ = 9 - 5) < 6 ? ref$ : 6;
当其中一个操作数等于(==或is,以及它们的否定)是正则表达式文字时,它将针对该操作数测试另一个操作数。相等编译为exec,因此您可以使用结果,而否定则简单地编译为test。
/^e(.*)/ is 'enter' #=> ["enter","nter"] /^e(.*)/ == 'zx' #=> null /moo/ != 'loo' #=> true
/^e(.*)/.exec('enter');
/^e(.*)/.exec('zx');
!/moo/.test('loo');
基础知识
true and false #=> false true && false #=> false true or false #=> true true || false #=> true not false #=> true !false #=> true
true && false; true && false; true || false; true || false; !false; !false;
其他语言中不常见的逻辑运算符 - 异或
false xor true #=> true false xor false #=> false 1 xor 0 #=> 1 1 xor 1 #=> false
!false !== !true && (false || true); !false !== !false && (false || false); !1 !== !0 && (1 || 0); !1 !== !1 && (1 || 1);
and、or和xor关闭隐式调用,而||和&&则不关闭。
even 0 and 3 #=> 3 even 0 && 3 #=> true
even(0) && 3; even(0 && 3);
您可以调用逻辑运算符。
(f or g) 1 (f and g or h) 3 4
f(1) || g(1); f(3, 4) && g(3, 4) || h(3, 4);
使用in检查元素是否在列表中;使用of检查键是否在对象中。
list = [7 8 9] 2 in [1 2 3 4 5] #=> true 3 in list #=> false \id of id: 23, name: \rogers #=> true
var list;
list = [7, 8, 9];
2 === 1 || 2 === 2 || 2 === 3 || 2 === 4 || 2 === 5;
in$(3, list);
'id' in {
id: 23,
name: 'rogers'
};
function in$(x, xs){
var i = -1, l = xs.length >>> 0;
while (++i < l) if (x === xs[i]) return true;
return false;
}
您可以将值传递进来,而不是一系列嵌套的函数调用。x |> f和f <| x等效于f(x)。
x = [1 2 3] |> reverse |> head #=> 3 y = reverse <| [1 2 3] #=> [3,2,1]
var x, y; x = head( reverse( [1, 2, 3])); y = reverse([1, 2, 3]);
您可以使用换行符来更好地分隔内容。
4 |> (+ 1) |> even #=> false
even(
(function(it){
return it + 1;
})(
4));
组合允许您通过组合一系列函数来创建函数。LiveScript有两个用于组合的运算符,前向>>和后向<<。
(f << g) x等效于f(g(x)),而(f >> g) x等效于g(f(x))。例如
odd = (not) << even odd 3 #=> true
var odd;
odd = compose$(even, not$);
odd(3);
function compose$() {
var functions = arguments;
return function() {
var i, result;
result = functions[0].apply(this, arguments);
for (i = 1; i < functions.length; ++i) {
result = functions[i](result);
}
return result;
};
}
function not$(x){ return !x; }
更清楚地说明这两个运算符之间的区别
add-two-times-two = (+ 2) >> (* 2) times-two-add-two = (+ 2) << (* 2) add-two-times-two 3 #=> (3+2)*2 => 10 times-two-add-two 3 #=> (3*2)+2 => 8
var addTwoTimesTwo, timesTwoAddTwo;
addTwoTimesTwo = compose$((function(it){
return it + 2;
}), (function(it){
return it * 2;
}));
timesTwoAddTwo = compose$((function(it){
return it * 2;
}), (function(it){
return it + 2;
}));
addTwoTimesTwo(3);
timesTwoAddTwo(3);
function compose$() {
var functions = arguments;
return function() {
var i, result;
result = functions[0].apply(this, arguments);
for (i = 1; i < functions.length; ++i) {
result = functions[i](result);
}
return result;
};
}
您可以使用空格点作为<<的别名,例如f . g,就像在Haskell中一样。
您可以将两个列表连接在一起
<[ one two three ]> ++ [\four] #=> ['one','two','three','four']
['one', 'two', 'three'].concat(['four']);
请注意,连接运算符必须在两侧都留有空格xs ++ ys,或者在两侧都不留空格xs++ys。如果只在一侧留有空格,则将其视为增量运算符。
当第一个是列表文字时的列表重复
[\ha] * 3 #=> ['ha','ha','ha']
['ha', 'ha', 'ha'];
当右侧操作数是字符串文字时的连接
<[ one two three ]> * \| #=> 'one|two|three'
['one', 'two', 'three'].join('|');
一元展开 - 当操作数是列表文字时,将一元运算符应用于每个项目
r = +...[4 5 6] #=> [+4, +5, +6]
t = typeof! ...[\b 5 {}] #=> ["String", "Number", "Object"]
c = ~...[4, 5] #=> [-5, -6]
++...player<[strength hp]>
# also works with -, --, typeof, ! and delete!
i = new ...[some, classes]
c = ^^...[copy, these, {}]
delete ...list[1, 2, 3]
do ...[a, b, c]
var r, t, c, i, toString$ = {}.toString;
r = [+4, +5, +6];
t = [toString$.call('b').slice(8, -1), toString$.call(5).slice(8, -1), toString$.call({}).slice(8, -1)];
c = [~4, ~5];
++player['strength'], ++player['hp'];
i = [new some, new classes];
c = [clone$(copy), clone$(these), clone$({})];
delete list[1], delete list[2], delete list[3];
a(), b(), c();
function clone$(it){
function fun(){} fun.prototype = it;
return new fun;
}
字符串连接
'hello' + ' ' + 'world' #=> 'hello world' string = 'say ' #=> 'say ' string += \yeah #=> 'say yeah'
var string; 'hello' + ' ' + 'world'; string = 'say '; string += 'yeah';
当第一个操作数是字符串文字时的字符串重复
'X' * 3 #=> 'XXX'
'XXX';
当右侧操作数是字符串或正则表达式文字时的字符串减法/除法 - 减法表示replace,除法表示split。
'say yeah' - /h/ #=> 'say yea' 'say yeah' / \y #=> ['sa',' ','eah']
'say yeah'.replace(/h/, '');
'say yeah'.split('y');
?运算符可以在各种上下文中用于检查是否存在。
bigfoot ? 'grizzly bear' #=> 'grizzly bear' string = \boom if window? #=> 'boom' document?.host #=> 'gkz.github.com'
var string;
(typeof bigfoot == 'undefined' || bigfoot === null) && 'grizzly bear';
if (typeof window != 'undefined' && window !== null) {
string = 'boom';
}
if (typeof document != 'undefined' && document !== null) {
document.host;
}
Instanceof - 右侧的列表文字将展开
new Date() instanceof Date #=> true new Date() instanceof [Date, Object] #=> true
var ref$; new Date() instanceof Date; (ref$ = new Date()) instanceof Date || ref$ instanceof Object;
Typeof - 添加一个感叹号以获得有用的替代方法
typeof /^/ #=> object typeof! /^/ #=> RegExp
var toString$ = {}.toString;
typeof /^/;
toString$.call(/^/).slice(8, -1);
Delete返回已删除项目的value
obj = {one: 1, two: 2}
r = delete obj.one
r #=> 1
var obj, r, ref$;
obj = {
one: 1,
two: 2
};
r = (ref$ = obj.one, delete obj.one, ref$);
r;
delete!类似于JavaScript中的delete,并且仅当属性存在且无法删除时才返回false,否则返回true。
obj = {one: 1, two: 2}
delete! obj.one #=> true
delete! Math.PI #=> false
var obj;
obj = {
one: 1,
two: 2
};
delete obj.one;
delete Math.PI;
属性复制 - 将可枚举属性从右复制到左,并计算为左。<<<用于自己的属性,<<<<用于所有属性。import和import all分别是这两个的别名,区别在于,如果您省略左操作数,则假定为this。
obj = {one: 1, two: 2}
obj <<< three: 3 #=> {one: 1, two: 2, three: 3}
{go: true} <<<< window
import obj
var obj;
obj = {
one: 1,
two: 2
};
obj.three = 3;
importAll$({
go: true
}, window);
import$(this, obj);
function importAll$(obj, src){
for (var key in src) obj[key] = src[key];
return obj;
}
function import$(obj, src){
var own = {}.hasOwnProperty;
for (var key in src) if (own.call(src, key)) obj[key] = src[key];
return obj;
}
克隆 - 创建操作数的原型克隆。它不会创建对象的深度克隆,而是将结果对象的原型设置为操作数。请记住,在序列化为JSON时会忽略原型。
obj = {one: 1}
obj2 = ^^obj
obj2.two = 2
obj2 #=> {one: 1, two: 2}
# above includes its prototype's properties
# JSON serialization would be just `{two: 2}`
obj #=> {one: 1}
var obj, obj2;
obj = {
one: 1
};
obj2 = clone$(obj);
obj2.two = 2;
obj2;
obj;
function clone$(it){
function fun(){} fun.prototype = it;
return new fun;
}
中缀with(也称为cloneport)结合了克隆和属性复制运算符,以便于创建对象。它等效于^^obj <<< obj2。请记住,克隆运算符创建原型克隆,并且原型不会在JSON中序列化。
girl = {name: \hanna, age: 22}
guy = girl with name: \john
guy #=> {name: 'john', age: 22}
# the above result include the object's prototype
# in the result - the actual JSON: {name: 'john'}
girl #=> {name: 'hanna', age: 22}
var girl, guy, ref$;
girl = {
name: 'hanna',
age: 22
};
guy = (ref$ = clone$(girl), ref$.name = 'john', ref$);
guy;
girl;
function clone$(it){
function fun(){} fun.prototype = it;
return new fun;
}
您可以部分应用运算符并将其用作函数
(+ 2) 4 #=> 6 (*) 4 3 #=> 12 (not) true #=> false (in [1 to 3]) 2 #=> true
(function(it){
return it + 2;
})(4);
curry$(function(x$, y$){
return x$ * y$;
})(4, 3);
not$(true);
(function(it){
return it === 1 || it === 2 || it === 3;
})(2);
function curry$(f, bound){
var context,
_curry = function(args) {
return f.length > 1 ? function(){
var params = args ? args.concat() : [];
context = bound ? context || this : this;
return params.push.apply(params, arguments) <
f.length && arguments.length ?
_curry.call(context, params) : f.apply(context, params);
} : f;
};
return _curry();
}
function not$(x){ return !x; }
通过使用export运算符而不是exports,您可以获得一种更简洁的定义模块的方法。
export func = -> export value export value-a, value-b, value-c export a: 1 b: -> 123 export class MyClass
var func, ref$, MyClass, out$ = typeof exports != 'undefined' && exports || this;
out$.func = func = function(){};
out$.value = value;
out$.valueA = valueA;
out$.valueB = valueB;
out$.valueC = valueC;
ref$ = out$;
ref$.a = 1;
ref$.b = function(){
return 123;
};
out$.MyClass = MyClass = (function(){
MyClass.displayName = 'MyClass';
var prototype = MyClass.prototype, constructor = MyClass;
function MyClass(){}
return MyClass;
}());
需要一系列模块会导致很多冗余代码。您可以使用require!摆脱这些冗余代码,它接受ID或字符串、数组或对象文字。
如果您需要名称中带有连字符的模块,则必须使用字符串文字。
您可以使用对象文字重命名您需要的内容。
您可以解构以获取value的内容。
require! lib
require! 'lib1'
require! prelude-ls # no
require! 'prelude-ls'
require! [fs, path]
require! <[ fs path ]>
require! jQuery: $
require! {
fs
path
lib: foo
}
var lib, lib1, preludeLs, fs, path, $, foo;
lib = require('lib');
lib1 = require('lib1');
preludeLs = require('preludeLs');
preludeLs = require('prelude-ls');
fs = require('fs');
path = require('path');
fs = require('fs');
path = require('path');
$ = require('jQuery');
fs = require('fs');
path = require('path');
foo = require('lib');
您可以轻松地使用解构需要模块的部分内容。
require! {
fs: filesystem
'prelude-ls': {map, id}
path: {join, resolve}:p
}
var filesystem, ref$, map, id, p, join, resolve;
filesystem = require('fs');
ref$ = require('prelude-ls'), map = ref$.map, id = ref$.id;
p = require('path'), join = p.join, resolve = p.resolve;
文件名会自动提取。
require! 'lib.js' require! './dir/lib1.js'
var lib, lib1;
lib = require('lib.js');
lib1 = require('./dir/lib1.js');
在 LiveScript 中定义函数非常轻量级
(x, y) -> x + y -> # an empty function times = (x, y) -> x * y # multiple lines, and be assigned to # a var like in JavaScript
var times;
(function(x, y){
return x + y;
});
(function(){});
times = function(x, y){
return x * y;
};
如您所见,函数定义要短得多!您可能还注意到我们省略了return。在LiveScript中,几乎所有内容都是表达式,并且自动返回达到的最后一个表达式。
您可以用感叹号!前缀函数箭头以抑制自动返回。
f = !-> 2 g = (x) !-> x + 2
var f, g;
f = function(){
2;
};
g = function(x){
x + 2;
};
在调用函数时,您可以省略括号,并且如果前面的项目不可调用,则可以省略分隔参数的逗号,就像在数组中一样。
x = 4 Math.pow x, 3 #=> 64 Math.pow 2 3 #=> 8
var x; x = 4; Math.pow(x, 3); Math.pow(2, 3);
如果您没有参数地调用函数,则可以使用感叹号! - 此外,在链接带感叹号的函数时,您不需要使用点。
f! [1 2 3].reverse!slice 1 #=> [2,1]
f(); [1, 2, 3].reverse().slice(1);
and、or、xor、带空格的.或?.都会关闭隐式调用 - 允许无括号链接。
$ \h1 .find \a .text! #=> LiveScript
$('h1').find('a').text();
您可以使用do调用没有参数的函数
do -> 3 + 2 #=> 5
(function(){
return 3 + 2;
})();
如果您在命名函数上使用do,当do不用作表达式时,命名函数将保持为函数语句。
i = 0 f 9 #=> 9 i #=> 1 do function f x ++i x i #=> 2
var i;
i = 0;
f(9);
i;
function f(x){
++i;
return x;
} f();
i;
您不能用隐式对象调用函数,如果您想这样做,可以使用do
func do a: 1 b: 2
func({
a: 1,
b: 2
});
do允许您在不添加额外括号的情况下执行许多操作。
pow do 1 2 h 1 do a: 2 b: 5
pow(1, 2);
h(1, {
a: 2,
b: 5
});
您还可以使用反引号`以中缀方式调用函数。
add = (x, y) -> x + y 3 `add` 4 #=> 7
var add;
add = function(x, y){
return x + y;
};
add(3, 4);
使用裸露的splat...调用函数意味着使用当前函数的参数调用它。在调用super时尤其有用。
f = (x, y) -> x + y g = (a, b) -> f ... g 3 4 #=> 7
var f, g;
f = function(x, y){
return x + y;
};
g = function(a, b){
return f.apply(this, arguments);
};
g(3, 4);
扩展参数
set-person-params = (
person # target object to set params
person.age
person.height
) -> person
person = set-person-params {}, 21, 180cm
#=> {age: 21, height: 180}
var setPersonParams, person;
setPersonParams = function(person, age, height){
person.age = age;
person.height = height;
return person;
};
person = setPersonParams({}, 21, 180);
这在使用this时尤其有用。
set-text = (@text) -> this
var setText;
setText = function(text){
this.text = text;
return this;
};
您可以设置默认参数
add = (x = 4, y = 3) -> x + y add 1 2 #=> 3 add 1 #=> 4 add! #=> 7
var add;
add = function(x, y){
x == null && (x = 4);
y == null && (y = 3);
return x + y;
};
add(1, 2);
add(1);
add();
...或者确实使用任何逻辑运算符(在参数中,x = 2只是x ? 2的语法糖)
add = (x && 4, y || 3) -> x + y add 1 2 #=> 6 add 2 0 #=> 7
var add;
add = function(x, y){
x && (x = 4);
y || (y = 3);
return x + y;
};
add(1, 2);
add(2, 0);
您还可以解构参数
set-cords = ({x, y}) -> "#x,#y"
set-cords y: 2, x: 3 #=> '3,2'
var setCords;
setCords = function(arg$){
var x, y;
x = arg$.x, y = arg$.y;
return x + "," + y;
};
setCords({
y: 2,
x: 3
});
...甚至在那些解构的参数上设置默认值(或使用任何逻辑),其功能类似于Python的关键字参数。
set-cords = ({x = 1, y = 3} = {}) -> "#x,#y"
set-cords y: 2, x: 3 #=> '3,2'
set-cords x: 2 #=> '2,3'
set-cords y: 7 #=> '1,7'
set-cords! #=> '1,3'
var setCords;
setCords = function(arg$){
var ref$, x, ref1$, y;
ref$ = arg$ != null
? arg$
: {}, x = (ref1$ = ref$.x) != null ? ref1$ : 1, y = (ref1$ = ref$.y) != null ? ref1$ : 3;
return x + "," + y;
};
setCords({
y: 2,
x: 3
});
setCords({
x: 2
});
setCords({
y: 7
});
setCords();
您也可以在参数中使用splat
f = (x, ...ys) -> x + ys.1 f 1 2 3 4 #=> 4
var f;
f = function(x){
var ys, res$, i$, to$;
res$ = [];
for (i$ = 1, to$ = arguments.length; i$ < to$; ++i$) {
res$.push(arguments[i$]);
}
ys = res$;
return x + ys[1];
};
f(1, 2, 3, 4);
您甚至可以在参数中使用一元运算符。您可以使用+和!!将参数分别转换为数字或布尔值,或者使用克隆运算符^^来确保您对对象的任何更改都不会反映在原始对象中。您仍然可以使用扩展参数,例如(!!x.x) ->。
f = (!!x) -> x
f 'truthy string' #=> true
g = (+x) -> x
g '' #=> 0
obj = {prop: 1}
h = (^^x) ->
x.prop = 99
x
h obj
obj.prop #=> 1
var f, g, obj, h;
f = function(x){
x = !!x;
return x;
};
f('truthy string');
g = function(x){
x = +x;
return x;
};
g('');
obj = {
prop: 1
};
h = function(x){
x = clone$(x);
x.prop = 99;
return x;
};
h(obj);
obj.prop;
function clone$(it){
function fun(){} fun.prototype = it;
return new fun;
}
柯里化函数非常强大。本质上,当调用时提供的参数少于定义的参数时,它们会返回一个部分应用函数。这意味着它返回一个函数,其参数是您未提供的参数,并且已绑定您提供的参数的值。它们在 LiveScript 中使用长箭头定义。也许一个例子会让事情更清楚
times = (x, y) --> x * y times 2, 3 #=> 6 (normal use works as expected) double = times 2 double 5 #=> 10
var times, double;
times = curry$(function(x, y){
return x * y;
});
times(2, 3);
double = times(2);
double(5);
function curry$(f, bound){
var context,
_curry = function(args) {
return f.length > 1 ? function(){
var params = args ? args.concat() : [];
context = bound ? context || this : this;
return params.push.apply(params, arguments) <
f.length && arguments.length ?
_curry.call(context, params) : f.apply(context, params);
} : f;
};
return _curry();
}
您可以使用长波浪箭头定义绑定柯里化函数:~~>
如果您不带任何参数调用柯里化函数,它将按原样计算,允许您使用默认参数。
f = (x = 5, y = 10) --> x + y f! #=> 15 g = f 20 g 7 #=> 27 g! #=> 30
var f, g;
f = curry$(function(x, y){
x == null && (x = 5);
y == null && (y = 10);
return x + y;
});
f();
g = f(20);
g(7);
g();
function curry$(f, bound){
var context,
_curry = function(args) {
return f.length > 1 ? function(){
var params = args ? args.concat() : [];
context = bound ? context || this : this;
return params.push.apply(params, arguments) <
f.length && arguments.length ?
_curry.call(context, params) : f.apply(context, params);
} : f;
};
return _curry();
}
您可以创建命名函数,其定义提升到作用域的顶部 - 这对于在文件末尾而不是顶部定义实用函数很有用。命名函数是常量,不能重新定义。
util! #=> 'available above declaration' util2! #=> 2 function util 'available above declaration' function util2 then 2
util();
util2();
function util(){
return 'available above declaration';
}
function util2(){
return 2;
}
您可以在函数定义前加上 ~ 以将其设为绑定函数。
~function add x, y @result = x + y
var this$ = this;
function add(x, y){
return this$.result = x + y;
}
您可以在其前面加上感叹号 ! 以抑制返回值。
util! #=> nothing !function util x then x
util();
function util(x){
x;
}
如果需要,您可以组合 ~ 和 ! 以创建一个绑定的非返回值函数。
使用波浪箭头 ~> 定义。对于柯里化和绑定函数,使用长波浪箭头 ~~>。在命名函数前加上 ~ 以将其设为绑定函数。
绑定函数的 this 是词法绑定的,而不是像通常那样动态绑定的。这意味着无论在哪个上下文中调用它们,其主体中 this 的值始终是定义它们时 this 的值。
obj = new @x = 10 @normal = -> @x @bound = ~> @x obj2 = x: 5 obj2.normal = obj.normal obj2.bound = obj.bound obj2.normal! #=> 5 obj2.bound! #=> 10
var obj, obj2;
obj = new function(){
var this$ = this;
this.x = 10;
this.normal = function(){
return this.x;
};
this.bound = function(){
return this$.x;
};
};
obj2 = {
x: 5
};
obj2.normal = obj.normal;
obj2.bound = obj.bound;
obj2.normal();
obj2.bound();
查看 OOP 部分,了解在类中使用绑定函数时的更多信息。
let 是 (function(a){...}.call(this, b)) 的简写。
let $ = jQuery $.isArray [] #=> true
(function($){
$.isArray([]);
}.call(this, jQuery));
您还可以使用 let 定义 this(也称为 @)。
x = let @ = a: 1, b: 2 @b ^ 3 x #=> 8
var x;
x = (function(){
return Math.pow(this.b, 3);
}.call({
a: 1,
b: 2
}));
x;
使用新上下文
dog = new
@name = \spot
@mutt = true
#=> {name: 'spot', mutt: true}
var dog;
dog = new function(){
this.name = 'spot';
this.mutt = true;
};
它们对高阶函数(如 map 和 filter)特别有用。
(.prop) 是 (it) -> it.prop 的简写。
map (.length), <[ hello there you ]> #=> [5,5,3] filter (.length < 4), <[ hello there you ]> #=> ['you']
map(function(it){
return it.length;
}, ['hello', 'there', 'you']);
filter(function(it){
return it.length < 4;
}, ['hello', 'there', 'you']);
您也可以用它来调用方法
map (.join \|), [[1 2 3], [7 8 9]] #=> ['1|2|3','7|8|9']
map(function(it){
return it.join('|');
}, [[1, 2, 3], [7, 8, 9]]);
(obj.) 是 (it) -> obj[it] 的简写。
obj = one: 1, two: 2, three: 3 map (obj.), <[ one three ]> #=> [1,3]
var obj;
obj = {
one: 1,
two: 2,
three: 3
};
map(function(it){
return obj[it];
}, ['one', 'three']);
回调非常有用。它们允许您取消嵌套回调。它们使用指向左边的箭头定义。所有语法与定义绑定函数 (<~)、柯里化函数 (<--, <~~)、抑制返回值 (<-!) 的常规箭头相同 - 只是方向相反。
<- $ alert \boom
$(function(){
return alert('boom');
});
它们可以接受参数,您还可以指定要放置参数的位置。
x <- map _, [1 to 3] x * 2 #=> [2, 4, 6]
map(function(x){
return x * 2;
}, [1, 2, 3]);
如果希望在回调之后有更多代码,可以使用 do 语句将其放在一边。
do data <-! $.get 'ajaxtest' $ '.result' .html data processed <-! $.get 'ajaxprocess', data $ '.result' .append processed alert 'hi'
$.get('ajaxtest', function(data){
$('.result').html(data);
$.get('ajaxprocess', data, function(processed){
$('.result').append(processed);
});
});
alert('hi');
如果您将在支持 async 和 await JavaScript 关键字的平台上运行编译后的代码,那么您可以在 LiveScript 中编写真正的异步函数。要将函数标记为异步,请在函数箭头中添加一个额外的 > (->>、~>>、-->> 等),或者对于命名函数,编写 async function 而不是 function。在异步函数内部,您可以像在 JavaScript 中一样使用 await 关键字。
f1 = (x) ->> await x async function f2 x a = await f1 x
var f1;
f1 = async function(x){
return (await x);
};
async function f2(x){
var a;
return a = (await f1(x));
}
您可以使用下划线 _ 作为占位符来部分应用函数。有时,您要处理的函数不是柯里化函数,或者如果它是柯里化函数,则参数的顺序不佳。在这些情况下,部分应用非常有用。
filter-nums = filter _, [1 to 5] filter-nums even #=> [2,4] filter-nums odd #=> [1,3,5] filter-nums (< 3) #=> [1,2]
var filterNums, slice$ = [].slice;
filterNums = partialize$.apply(this, [filter, [void 8, [1, 2, 3, 4, 5]], [0]]);
filterNums(even);
filterNums(odd);
filterNums((function(it){
return it < 3;
}));
function partialize$(f, args, where){
var context = this;
return function(){
var params = slice$.call(arguments), i,
len = params.length, wlen = where.length,
ta = args ? args.concat() : [], tw = where ? where.concat() : [];
for(i = 0; i < len; ++i) { ta[tw[0]] = params[i]; tw.shift(); }
return len < wlen && len ?
partialize$.apply(context, [f, ta, tw]) : f.apply(context, ta);
};
}
如果您不带任何参数调用部分应用函数,它将按原样执行,而不是返回自身,允许您使用默认参数。
如果使用的函数没有很好的参数顺序并且不是柯里化函数(例如 underscore.js 中的函数),则部分应用函数对于管道也确实很有用。
[1 2 3] |> _.map _, (* 2) |> _.reduce _, (+), 0 #=> 12
_.reduce(_.map([1, 2, 3], (function(it){
return it * 2;
})), curry$(function(x$, y$){
return x$ + y$;
}), 0);
function curry$(f, bound){
var context,
_curry = function(args) {
return f.length > 1 ? function(){
var params = args ? args.concat() : [];
context = bound ? context || this : this;
return params.push.apply(params, arguments) <
f.length && arguments.length ?
_curry.call(context, params) : f.apply(context, params);
} : f;
};
return _curry();
}
如果您只有一个参数,可以使用 it 访问它,而无需定义参数。
f = -> it + 2 f 3 #=> 5
var f;
f = function(it){
return it + 2;
};
f(3);
您可以使用简写 & 访问 arguments 对象。第一个参数是 &0,第二个是 &1,依此类推。单独的 & 是整个 arguments。
add-three-numbers = -> &0 + &1 + &2 add-three-numbers 1 2 3 #=> 6
var addThreeNumbers;
addThreeNumbers = function(){
return arguments[0] + arguments[1] + arguments[2];
};
addThreeNumbers(1, 2, 3);
请注意,在这种情况下柯里化不起作用,因为 add-three-numbers 中声明的参数数量为 0。
您可以在 LiveScript 代码中使用生成器和 yield!简要概述
function* f
yield "foo"
g = ->*
yield from f!
yield "bar"
h = g!
h.next!.value + h.next!.value #=> "foobar"
var g, h;
function* f(){
return (yield "foo");
}
g = function*(){
(yield* f());
return (yield "bar");
};
h = g();
h.next().value + h.next().value;
您可以通过在 function 关键字后附加星号 * 或将其附加到 LiveScript 的箭头表示法来创建生成器。这适用于我们拥有的各种箭头。
yield 与 JavaScript 中的相同,yield from 是 JavaScript 中的 yield*。
要使用 node 0.11 运行使用生成器和 yield 的代码,请使用 --harmony 标志。如果直接使用 lsc 运行,请使用 lsc file.ls --nodejs --harmony 将 harmony 标志传递给 node。
有几种方法可以格式化 if 语句。(请注意,if 语句实际上是一个表达式,可以作为表达式使用)。
标准的
if 2 + 2 == 4 'something' else 'something else' if 2 + 2 == 4 then 'something' else 'something else' if 2 + 2 == 4 then 'something' else 'something else'
if (2 + 2 === 4) {
'something';
} else {
'something else';
}
if (2 + 2 === 4) {
'something';
} else {
'something else';
}
if (2 + 2 === 4) {
'something';
} else {
'something else';
}
else 是可选的,可以添加更多 else if。
if 2 + 2 == 4 'something' if 2 + 2 == 6 'something' else if 2 + 2 == 5 'something else' else 'the default'
if (2 + 2 === 4) {
'something';
}
if (2 + 2 === 6) {
'something';
} else if (2 + 2 === 5) {
'something else';
} else {
'the default';
}
它可以用作表达式
result = if 2 / 2 is 0
then 'something'
else 'something else'
var result; result = 2 / 2 === 0 ? 'something' : 'something else';
它也可以用作后缀 - 它的优先级低于赋值,这使其很有用
x = 10 x = 3 if 2 + 2 == 4 x #=> 3
var x;
x = 10;
if (2 + 2 === 4) {
x = 3;
}
x;
unless 等效于 if not。
unless 2 + 2 == 5 'something' x = 10 x = 3 unless 2 + 2 == 5
var x;
if (2 + 2 !== 5) {
'something';
}
x = 10;
if (2 + 2 !== 5) {
x = 3;
}
that 隐式引用条件的值。它将解开存在性检查。
time = days: 365 half-year = that / 2 if time.days #=> 182.5 if /^e(.*)/ == 'enter' that.1 #=> 'nter' if half-year? that * 2 #=> 365
var time, that, halfYear;
time = {
days: 365
};
if (that = time.days) {
halfYear = that / 2;
}
if (that = /^e(.*)/.exec('enter')) {
that[1];
}
if ((that = halfYear) != null) {
that * 2;
}
for 循环有三种基本形式。一种遍历数字范围,一种遍历列表中的项目,一种遍历对象的键和值。
我们首先检查遍历数字范围的 for 循环。它的结构为:for (let) (VAR) (from NUM) (to|til NUM) (by NUM) (when COND) - (几乎所有内容都是可选的)。
let 的作用是将循环体包装在一个立即调用的函数表达式中,当您在循环中创建函数并希望函数在调用时循环变量为当前值(而不是最终值)时,这很有用。它也很有用,因为这意味着循环中的变量不会暴露在循环周围的作用域中。
从一个数字开始计数,如果省略,则默认为 0。
向上计数 to 并包括一个数字,或向上计数 til(但不包括)一个数字。
by 是步长值,默认为 1。
when(别名 case、|)是可选的保护。
如果用作表达式,循环将计算为列表。
for i from 1 to 10 by 3 i
var i$, i;
for (i$ = 1; i$ <= 10; i$ += 3) {
i = i$;
i;
}
for ... in 循环遍历列表。它们的结构为:for (let) (VAL-VAR)(, INDEX-VAR) in EXP (by NUM) (when COND) - 同样,几乎所有内容都是可选的。
let、by 和 when 与之前相同。
VAL-VAR 计算为当前值,而 INDEX-VAR 计算为列表的当前索引。两者都是可选的。
EXP 应计算为数组。
for x in [1 2 3] x xs = for let x, i in [1 to 10] by 2 when x % 3 == 0 -> i + x xs[0]! #=> 5 xs[1]! #=> 17
var i$, ref$, len$, x, xs, res$, i;
for (i$ = 0, len$ = (ref$ = [1, 2, 3]).length; i$ < len$; ++i$) {
x = ref$[i$];
x;
}
res$ = [];
for (i$ = 0, len$ = (ref$ = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).length; i$ < len$; i$ += 2) {
i = i$;
x = ref$[i$];
if (x % 3 === 0) {
res$.push((fn$.call(this, i, x)));
}
}
xs = res$;
xs[0]();
xs[1]();
function fn$(i, x){
return function(){
return i + x;
};
}
for ... of 循环遍历对象。它们的结构为:for (own) (let) (KEY-VAR)(, VAL-VAR) of EXP (when COND) - 同样,几乎所有内容都是可选的。
let 和 when 与之前相同。
own 对属性使用 hasOwnProperty 检查,停止原型链中更高层属性的迭代。
KEY-VAR 计算为属性的键,VAL-VAR 计算为属性值。两者都是可选的。
EXP 应计算为对象。
for k, v of {a: 1, b: 2}
"#k#v"
xs = for own let key, value of {a: 1, b: 2, c: 3, d: 4} when value % 2 == 0
-> key + value
xs[0]! #=> 'b2'
xs[1]! #=> 'd4'
var k, ref$, v, xs, res$, i$, key, value, own$ = {}.hasOwnProperty;
for (k in ref$ = {
a: 1,
b: 2
}) {
v = ref$[k];
k + "" + v;
}
res$ = [];
for (i$ in ref$ = {
a: 1,
b: 2,
c: 3,
d: 4
}) if (own$.call(ref$, i$)) {
key = i$;
value = ref$[i$];
if (value % 2 === 0) {
res$.push((fn$.call(this, key, value)));
}
}
xs = res$;
xs[0]();
xs[1]();
function fn$(key, value){
return function(){
return key + value;
};
}
常规嵌套循环将计算为列表的列表。
result = for x to 3
for y to 2
x + y
result #=> [[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5]]
var result, res$, i$, x, lresult$, j$, y;
res$ = [];
for (i$ = 0; i$ <= 3; ++i$) {
x = i$;
lresult$ = [];
for (j$ = 0; j$ <= 2; ++j$) {
y = j$;
lresult$.push(x + y);
}
res$.push(lresult$);
}
result = res$;
result;
您可以在 in/of 循环中省略一个或两个变量。
res = for , i in [1 2 3] i res #=> [0, 1, 2] for til 3 then func! # calls func three times [6 for til 3] #=> [6, 6, 6]
var res, res$, i$, len$, i;
res$ = [];
for (i$ = 0, len$ = [1, 2, 3].length; i$ < len$; ++i$) {
i = i$;
res$.push(i);
}
res = res$;
res;
for (i$ = 0; i$ < 3; ++i$) {
func();
}
for (i$ = 0; i$ < 3; ++i$) {
6;
}
列表推导式始终生成列表。嵌套推导式生成扁平化的列表。
[x + 1 for x to 10 by 2 when x isnt 4] #=> [1,3,7,9,11] ["#x#y" for x in [\a \b] for y in [1 2]] #=> ['a1','a2','b1','b2']
var i$, x, ref$, len$, j$, ref1$, len1$, y;
for (i$ = 0; i$ <= 10; i$ += 2) {
x = i$;
if (x !== 4) {
x + 1;
}
}
for (i$ = 0, len$ = (ref$ = ['a', 'b']).length; i$ < len$; ++i$) {
x = ref$[i$];
for (j$ = 0, len1$ = (ref1$ = [1, 2]).length; j$ < len1$; ++j$) {
y = ref1$[j$];
x + "" + y;
}
}
您可以使用空格来更好地格式化推导式。
[{id:id1, name, age} for {id:id1, name} in table1
for {id:id2, age} in table2
when id1 is id2]
var i$, ref$, len$, ref1$, id1, name, j$, len1$, ref2$, id2, age;
for (i$ = 0, len$ = (ref$ = table1).length; i$ < len$; ++i$) {
ref1$ = ref$[i$], id1 = ref1$.id, name = ref1$.name;
for (j$ = 0, len1$ = (ref1$ = table2).length; j$ < len1$; ++j$) {
ref2$ = ref1$[j$], id2 = ref2$.id, age = ref2$.age;
if (id1 === id2) {
({
id: id1,
name: name,
age: age
});
}
}
}
您可以使用级联来隐式引用正在映射的值。
[.. + 1 for [1 2 3]] #=> [2, 3, 4]
list-of-obj =
* name: 'Alice'
age: 23
* name: 'Betty'
age: 26
[..name for list-of-obj] #=> ['Alice', 'Betty']
var i$, x$, ref$, len$, listOfObj, y$;
for (i$ = 0, len$ = (ref$ = [1, 2, 3]).length; i$ < len$; ++i$) {
x$ = ref$[i$];
x$ + 1;
}
listOfObj = [
{
name: 'Alice',
age: 23
}, {
name: 'Betty',
age: 26
}
];
for (i$ = 0, len$ = listOfObj.length; i$ < len$; ++i$) {
y$ = listOfObj[i$];
y$.name;
}
对象推导式生成一个对象。
{[key, val * 2] for key, val of {a: 1, b: 2}}
#=> {a: 2, b: 4}
var key, ref$, val;
for (key in ref$ = {
a: 1,
b: 2
}) {
val = ref$[key];
[key, val * 2];
}
while 循环
i = 0 list = [1 to 10] while n < 9 n = list[++i]
var i, list, n;
i = 0;
list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
while (n < 9) {
n = list[++i];
}
until 等效于 while not。
while/until 还可以接受 when 保护和一个可选的 else 子句,该子句如果根本没有运行则运行。
i = 1 list = [1 to 10] until i > 7 when n isnt 99 n = list[++i] else 10
var i, list, yet$, n;
i = 1;
list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
for (yet$ = true; !(i > 7);) {
yet$ = false;
if (n !== 99) {
n = list[++i];
}
} if (yet$) {
10;
}
Do while
i = 0 list = [1 to 10] do i++ while list[i] < 9
var i, list;
i = 0;
list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
do {
i++;
} while (list[i] < 9);
While 还可以接受更新子句。
i = 0 list = [1 to 10] while list[i] < 9, i++ then i
var i, list;
i = 0;
list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
for (; list[i] < 9; i++) {
i;
}
While true
i = 0
loop
\ha
break if ++i > 20
i = 0
for ever
\ha
if ++i > 20
break
var i;
i = 0;
for (;;) {
'ha';
if (++i > 20) {
break;
}
}
i = 0;
for (;;) {
'ha';
if (++i > 20) {
break;
}
}
自动插入 break,并且允许多个条件。
switch 6 case 1 then \hello case 2, 4 then \boom case 6 'here it is' default \something
switch (6) {
case 1:
'hello';
break;
case 2:
case 4:
'boom';
break;
case 6:
'here it is';
break;
default:
'something';
}
如果您切换到没有任何内容,则切换到 true。(它编译为切换到 false,以便它可以使用一个 ! 而不是两个 ! 将 case 转换为布尔值)。
switch case 5 == 6 \never case false 'also never' case 6 / 2 is 3 'here'
switch (false) {
case 5 !== 6:
'never';
break;
case !false:
'also never';
break;
case 6 / 2 !== 3:
'here';
}
您可以使用 fallthrough 停止自动插入 break。它必须是 case 块的最后一个表达式。此外,您可以将 switch 语句用作表达式。
result = switch 6 case 6 something = 5 fallthrough case 4 'this is it' result #=> 'this is it'
var result, something;
result = (function(){
switch (6) {
case 6:
something = 5;
// fallthrough
case 4:
return 'this is it';
}
}());
result;
| 是 case 的别名,=> 是 then 的别名。| otherwise 和 | _ 是 default 的别名。
switch 'moto' | "some thing" => \hello | \explosion \bomb => \boom | <[ the moto ? ]> => 'here it is' | otherwise => \something
switch ('moto') {
case "some thing":
'hello';
break;
case 'explosion':
case 'bomb':
'boom';
break;
case 'the':
case 'moto':
case '?':
'here it is';
break;
default:
'something';
}
您可以将 that 与 switch 语句一起使用
switch num | 2 => console.log that | otherwise => console.log that
var that;
switch (that = num) {
case 2:
console.log(that);
break;
default:
console.log(that);
}
如果下一个标记是 case,则在箭头 (例如 ->)、: 和 = 后添加隐式 switch。
func = (param) ->
| param.length < 5 => param.length
| otherwise => param.slice 3
func 'hello' #=> lo
state = | 2 + 2 is 5 => 'I love Big Brother'
| _ => 'I love Julia'
var func, state;
func = function(param){
switch (false) {
case !(param.length < 5):
return param.length;
default:
return param.slice(3);
}
};
func('hello');
state = (function(){
switch (false) {
case 2 + 2 !== 5:
return 'I love Big Brother';
default:
return 'I love Julia';
}
}());
您还可以使用 CoffeeScript 样式的 switch 语句。
day = \Sun
switch day
when "Mon" then 'go to work'
when "Tue" then 'go to a movie'
when "Thu" then 'go drinking'
when "Fri", "Sat"
'go dancing'
when "Sun" then 'drink more'
else 'go to work'
var day;
day = 'Sun';
switch (day) {
case "Mon":
'go to work';
break;
case "Tue":
'go to a movie';
break;
case "Thu":
'go drinking';
break;
case "Fri":
case "Sat":
'go dancing';
break;
case "Sun":
'drink more';
break;
default:
'go to work';
}
基本赋值与您预期的一样,variable = value,并且不需要变量声明。但是,与 CoffeeScript 不同,您必须使用 := 来修改上层作用域中的变量。
x = 10 do -> x = 5 x #=> 10 do -> x := 2 x #=> 2
var x;
x = 10;
(function(){
var x;
return x = 5;
})();
x;
(function(){
return x = 2;
})();
x;
几乎所有内容都是表达式,这意味着您可以执行以下操作
x = if 2 + 2 == 4
then 10
else 0
x #=> 10
var x; x = 2 + 2 === 4 ? 10 : 0; x;
诸如循环、switch 语句,甚至 try/catch 语句都是表达式。
如果只想声明一个变量而不初始化它,可以使用 var。
var x
var x;
您也可以使用const在LiveScript中声明常量。它们在编译时进行检查 - 编译后的JS没有区别。
尝试编译以下内容
const x = 10 x = 0
导致在第 2 行重新声明常量“x”。
但是,如果将对象声明为常量,则不会冻结它们 - 您仍然可以修改其属性。如果使用-k或--const标志进行编译,则可以强制所有变量都为常量。
复合赋值
(?、|| 或 && 可以作为任何复合赋值的前缀。)
x = 2 #=> 2 x += 2 #=> 4 x -= 1 #=> 3 x *= 3 #=> 9 x /= 3 #=> 3 x %= 3 #=> 0 x %%= 3 #=> 0 x <?= -1 #=> -1 x >?= 2 #=> 2 x **= 2 #=> 4 x ^= 2 #=> 16 x ?= 10 x #=> 16 x ||= 5 #=> 16 x &&= 5 #=> 5 x &&+= 3 #=> 8 x ?*= 2 #=> 16 xs = [1 2] xs ++= [3] xs #=> [1 2 3]
var x, ref$, xs; x = 2; x += 2; x -= 1; x *= 3; x /= 3; x %= 3; x = ((x) % (ref$ = 3) + ref$) % ref$; x <= (ref$ = -1) || (x = ref$); x >= 2 || (x = 2); x = Math.pow(x, 2); x = Math.pow(x, 2); x == null && (x = 10); x; x || (x = 5); x && (x = 5); x && (x += 3); x != null && (x *= 2); xs = [1, 2]; xs = xs.concat([3]); xs;
一元赋值
y = \45 + = y #=> 45 (make into number) !! = y #=> true (make into boolean) -~-~ = y #=> 3 (intcasting bicrement)
var y; y = '45'; y = +y; y = !!y; y = -~-~y;
赋值默认值 - 您可以使用 ||、&& 和 ?。
您可以在函数参数中使用 = 代替 ?。
x ? y = 10 y #=> 10 f = (z = 7) -> z f 9 #=> 9 f! #=> 7
var y, f;
(typeof x == 'undefined' || x === null) && (y = 10);
y;
f = function(z){
z == null && (z = 7);
return z;
};
f(9);
f();
浸泡赋值 - 仅当右操作数存在时执行赋值
age = 21 x? = age x #=> 21 x? = years x #=> 21
var age, x;
age = 21;
if (age != null) {
x = age;
}
x;
if (typeof years != 'undefined' && years !== null) {
x = years;
}
x;
解构是从变量中提取值的一种强大方法。您无需分配给简单变量,而是可以分配给数据结构,从而提取值。例如
[first, second] = [1, 2] first #=> 1 second #=> 2
var ref$, first, second; ref$ = [1, 2], first = ref$[0], second = ref$[1]; first; second;
您还可以使用 splat
[head, ...tail] = [1 to 5] head #=> 1 tail #=> [2,3,4,5] [first, ...middle, last] = [1 to 5] first #=> 1 middle #=> [2,3,4] last #=> 5
var ref$, head, tail, first, i$, middle, last, slice$ = [].slice; ref$ = [1, 2, 3, 4, 5], head = ref$[0], tail = slice$.call(ref$, 1); head; tail; ref$ = [1, 2, 3, 4, 5], first = ref$[0], middle = 1 < (i$ = ref$.length - 1) ? slice$.call(ref$, 1, i$) : (i$ = 1, []), last = ref$[i$]; first; middle; last;
...以及对象!
{name, age} = {weight: 110, name: 'emma', age: 20}
name #=> 'emma'
age #=> 20
var ref$, name, age;
ref$ = {
weight: 110,
name: 'emma',
age: 20
}, name = ref$.name, age = ref$.age;
name;
age;
您还可以使用 :label 为正在解构的实体命名,以及任意嵌套解构。
[[x, ...xs]:list1, [y, ...ys]:list2] = [[1,2,3],[4,5,6]] x #=> 1 xs #=> [2,3] list1 #=> [1,2,3] y #=> 4 ys #=> [5,6] list2 #=> [4,5,6]
var ref$, list1, x, xs, list2, y, ys, slice$ = [].slice; ref$ = [[1, 2, 3], [4, 5, 6]], list1 = ref$[0], x = list1[0], xs = slice$.call(list1, 1), list2 = ref$[1], y = list2[0], ys = slice$.call(list2, 1); x; xs; list1; y; ys; list2;
轻松设置列表和对象的属性。
mitch =
age: 21
height: 180cm
pets: [\dog, \goldfish]
phile = {}
phile{height, pets} = mitch
phile.height #=> 180
phile.pets #=> ['dog', 'goldfish']
var mitch, phile;
mitch = {
age: 21,
height: 180,
pets: ['dog', 'goldfish']
};
phile = {};
phile.height = mitch.height, phile.pets = mitch.pets;
phile.height;
phile.pets;
标准的
[1 2 3][1] #=> 2
{a: 1, b: 2}.b #=> 2
[1, 2, 3][1];
({
a: 1,
b: 2
}).b;
点访问 - 点运算符可以接受比标识符更多的东西作为其右操作数,包括数字、字符串、括号、方括号和花括号。
x = "hello world": [4 [5 boom: 6]] x.'hello world'.1.[0] #=> 5
var x;
x = {
"hello world": [
4, [
5, {
boom: 6
}
]
]
};
x['hello world'][1][0];
使用 .= 进行访问赋值。
document.title .= to-upper-case! #=> LIVESCRIPT ...
document.title = document.title.toUpperCase();
数组切片和拼接
list = [1 2 3 4 5] list[2, 4] #=> [3,5] list[1 to 3] #=> [2,3,4] list[1 til 3] #=> [2,3] list[1 til 4 by 2] #=> [2,4] list[1 til 3] = [7 8] list #=> [1,7,8,4,5]
var list, ref$; list = [1, 2, 3, 4, 5]; [list[2], list[4]]; [list[1], list[2], list[3]]; [list[1], list[2]]; [list[1], list[3]]; ref$ = [7, 8], list[1] = ref$[0], list[2] = ref$[1]; list;
对象切片
obj = one: 1, two: 2
obj{first: one, two} #=> {first: 1, two: 2}
var obj;
obj = {
one: 1,
two: 2
};
({
first: obj.one,
two: obj.two
});
长度星号 *。
list = [1 2 3 4 5] list[*] = 6 list #=> [1,2,3,4,5,6] list[*-1] #=> 6
var list; list = [1, 2, 3, 4, 5]; list[list.length] = 6; list; list[list.length - 1];
半自动赋予 .{}、.[] 确保属性作为对象或数组存在。
x = "hello world": [4 [5 boom: 6]]
x.[]'hello world'.1.{}1.boom #=> 6
x.[]arr.{}1.y = 9
x.arr.1.y #=> 9
var x, ref$;
x = {
"hello world": [
4, [
5, {
boom: 6
}
]
]
};
((ref$ = (x['hello world'] || (x['hello world'] = []))[1])[1] || (ref$[1] = {})).boom;
((ref$ = x.arr || (x.arr = []))[1] || (ref$[1] = {})).y = 9;
x.arr[1].y;
绑定访问 .~ 将对象的 method 检索为绑定到该对象。使用自动点插入,您只需使用 ~。
请注意,这与 Function 上的 .bind 方法不同。使用 .~,方法是动态绑定的;foo~bar 将引用调用绑定函数时 foo 上 bar 的值,而不是进行绑定访问时 bar 的值。
obj = x: 5 add: (y) -> @x + y target = x: 600 not-bound: obj.add bound: obj~add target.not-bound 5 #=> 605 target.bound 5 #=> 10 # Binding access is dynamic: obj.add = (y) -> @x + 1000*y target.bound 5 #=> 5005
var obj, target;
obj = {
x: 5,
add: function(y){
return this.x + y;
}
};
target = {
x: 600,
notBound: obj.add,
bound: bind$(obj, 'add')
};
target.notBound(5);
target.bound(5);
obj.add = function(y){
return this.x + 1000 * y;
};
target.bound(5);
function bind$(obj, key, target){
return function(){ return (target || obj)[key].apply(obj, arguments) };
}
级联始终计算为正在访问的项目,而不是访问操作的返回值。
漂亮的链式调用
a = [2 7 1 8]
..push 3
..shift!
..sort!
a #=> [1,3,7,8]
document.query-selector \h1
..style
..color = \red
..font-size = \large
..inner-HTML = 'LIVESCRIPT!'
var x$, a, y$, z$;
x$ = a = [2, 7, 1, 8];
x$.push(3);
x$.shift();
x$.sort();
a;
y$ = document.querySelector('h1');
z$ = y$.style;
z$.color = 'red';
z$.fontSize = 'large';
y$.innerHTML = 'LIVESCRIPT!';
级联是可调用的,并且可以包含任意代码。
console.log x = 1 y = 2 .. x, y # prints `1 2` to the console
var x$, x, y; x$ = console.log; x = 1; y = 2; x$(x, y);
您可以使用 with 指定要级联的前一个表达式的部分。
x = with {a: 1, b: 2}
..a = 7
..b += 9
x #=> {a: 7, b: 11}
var x, x$;
x = (x$ = {
a: 1,
b: 2
}, x$.a = 7, x$.b += 9, x$);
x;
您可以使用恰如其分命名的 throw 抛出异常。
throw new Error 'an error has occurred!'
throw new Error('an error has occurred!');
可以使用try catch finally块捕获并处理异常。catch和finally都是可选的。
try块会被尝试执行。如果发生异常,则执行catch块。它会接收异常对象作为参数。如果不指定此变量的名称,则默认为e。与JavaScript不同,异常变量的作用域限定在最近的函数内,而不是catch块内。如果需要,可以解构异常对象。
try
...
try
...
catch
2 + 2
e.message
x = try
...
catch {message}
message
x #=> unimplemented
var e, x, message;
try {
throw Error('unimplemented');
} catch (e$) {}
try {
throw Error('unimplemented');
} catch (e$) {
e = e$;
2 + 2;
}
e.message;
x = (function(){
try {
throw Error('unimplemented');
} catch (e$) {
message = e$.message;
return message;
}
}());
x;
finally块在try或catch之后执行,无论发生了什么。
try ... catch handle-exception e finally do-something! try ... finally do-something!
var e;
try {
throw Error('unimplemented');
} catch (e$) {
e = e$;
handleException(e);
} finally {
doSomething();
}
try {
throw Error('unimplemented');
} finally {
doSomething();
}
类是对构造函数定义和原型设置的简单语法糖。
构造函数定义为类定义顶层的函数字面量。
其原型的属性由顶层的对象字面量定义。
class A
(num) ->
@x = num
property: 1
method: (y) ->
@x + @property + y
a = new A 3
a.x #=> 3
a.property #=> 1
a.method 6 #=> 10
var A, a;
A = (function(){
A.displayName = 'A';
var prototype = A.prototype, constructor = A;
function A(num){
this.x = num;
}
A.prototype.property = 1;
A.prototype.method = function(y){
return this.x + this.property + y;
};
return A;
}());
a = new A(3);
a.x;
a.property;
a.method(6);
静态属性(附加到构造函数的属性)通过在顶层向this添加属性来定义。这些属性可以通过访问constructor(简写@@)在方法中访问。
class A
@static-prop = 10
get-static: ->
@@static-prop + 2
A.static-prop #=> 10
a = new A
a.get-static! #=> 12
var A, a;
A = (function(){
A.displayName = 'A';
var prototype = A.prototype, constructor = A;
A.staticProp = 10;
A.prototype.getStatic = function(){
return constructor.staticProp + 2;
};
function A(){}
return A;
}());
A.staticProp;
a = new A;
a.getStatic();
私有静态属性在类体中定义为普通的变量。(注意:JavaScript和LiveScript中都不支持私有实例属性。)
class A
secret = 10
get-secret: ->
secret
a = new A
a.get-secret! #=> 10
var A, a;
A = (function(){
A.displayName = 'A';
var secret, prototype = A.prototype, constructor = A;
secret = 10;
A.prototype.getSecret = function(){
return secret;
};
function A(){}
return A;
}());
a = new A;
a.getSecret();
您可以定义绑定方法(使用~>),其this的定义绑定到实例。
class A
x: 10
bound-func: (x) ~>
@x
reg-func: (x) ->
@x
a = new A
obj =
x: 1
bound: a.bound-func
reg: a.reg-func
obj.bound! #=> 10
obj.reg! #=> 1
var A, a, obj;
A = (function(){
A.displayName = 'A';
var prototype = A.prototype, constructor = A;
A.prototype.x = 10;
A.prototype.boundFunc = function(x){
return this.x;
};
A.prototype.regFunc = function(x){
return this.x;
};
function A(){
this.boundFunc = bind$(this, 'boundFunc', prototype);
}
return A;
}());
a = new A;
obj = {
x: 1,
bound: a.boundFunc,
reg: a.regFunc
};
obj.bound();
obj.reg();
function bind$(obj, key, target){
return function(){ return (target || obj)[key].apply(obj, arguments) };
}
您可以使用对象设置参数简写轻松地在构造函数和方法中设置属性。
class A
(@x) ->
f: (@y) ->
@x + @y
a = new A 2
a.x #=> 2
a.f 3 #=> 5
a.y #=> 3
var A, a;
A = (function(){
A.displayName = 'A';
var prototype = A.prototype, constructor = A;
function A(x){
this.x = x;
}
A.prototype.f = function(y){
this.y = y;
return this.x + this.y;
};
return A;
}());
a = new A(2);
a.x;
a.f(3);
a.y;
如果将构造函数定义为绑定函数~>,则在创建新实例时无需使用new。
class A (@x) ~> a = A 4 a.x #=> 4
var A, a;
A = (function(){
A.displayName = 'A';
var prototype = A.prototype, constructor = A;
function A(x){
var this$ = this instanceof ctor$ ? this : new ctor$;
this$.x = x;
return this$;
} function ctor$(){} ctor$.prototype = prototype;
return A;
}());
a = A(4);
a.x;
对于更高级别的库和框架,可以通过设置属性constructor$$将构造函数定义为外部函数。不建议在常规编码中这样做。
f = (@x) -> class A constructor$$: f a = new A 5 a.x #=> 5
var f, A, a;
f = function(x){
this.x = x;
};
A = (function(){
A.displayName = 'A';
var constructor$$, prototype = A.prototype, constructor = A;
function A(){
return constructor$$.apply(this, arguments);
}
constructor$$ = f;
return A;
}());
a = new A(5);
a.x;
可以使用extends继承。
class A
->
@x = 1
@static-prop = 8
method: ->
@x + 2
class B extends A
->
@x = 10
B.static-prop #=> 8
b = new B
b.x #=> 10
b.method! #=> 12
var A, B, b;
A = (function(){
A.displayName = 'A';
var prototype = A.prototype, constructor = A;
function A(){
this.x = 1;
}
A.staticProp = 8;
A.prototype.method = function(){
return this.x + 2;
};
return A;
}());
B = (function(superclass){
var prototype = extend$((import$(B, superclass).displayName = 'B', B), superclass).prototype, constructor = B;
function B(){
this.x = 10;
}
return B;
}(A));
B.staticProp;
b = new B;
b.x;
b.method();
function extend$(sub, sup){
function fun(){} fun.prototype = (sub.superclass = sup).prototype;
(sub.prototype = new fun).constructor = sub;
if (typeof sup.extended == 'function') sup.extended(sub);
return sub;
}
function import$(obj, src){
var own = {}.hasOwnProperty;
for (var key in src) if (own.call(src, key)) obj[key] = src[key];
return obj;
}
这在使用super时尤其有用。如果单独使用,super是对应函数的引用。如果要使用所有参数调用它,请使用super ...。
class A
->
@x = 1
method: (num) ->
@x + num
class B extends A
->
@y = 2
super!
method: (num) ->
@y + super ...
b = new B
b.y #=> 2
b.method 10 #=> 13
var A, B, b;
A = (function(){
A.displayName = 'A';
var prototype = A.prototype, constructor = A;
function A(){
this.x = 1;
}
A.prototype.method = function(num){
return this.x + num;
};
return A;
}());
B = (function(superclass){
var prototype = extend$((import$(B, superclass).displayName = 'B', B), superclass).prototype, constructor = B;
function B(){
this.y = 2;
B.superclass.call(this);
}
B.prototype.method = function(num){
return this.y + superclass.prototype.method.apply(this, arguments);
};
return B;
}(A));
b = new B;
b.y;
b.method(10);
function extend$(sub, sup){
function fun(){} fun.prototype = (sub.superclass = sup).prototype;
(sub.prototype = new fun).constructor = sub;
if (typeof sup.extended == 'function') sup.extended(sub);
return sub;
}
function import$(obj, src){
var own = {}.hasOwnProperty;
for (var key in src) if (own.call(src, key)) obj[key] = src[key];
return obj;
}
您可以通过implements使用mixin。您只能从一个类继承,但可以混合任意数量的对象。请记住,如果要实现一个类,而不仅仅是一个简单对象,则必须实现类的原型。
Renameable =
set-name: (@name) ->
get-name: -> @name ? @id
class A implements Renameable
->
@id = Math.random! * 1000
a = new A
a.get-name! #=> some random number
a.set-name 'moo'
a.get-name! #=> 'moo'
var Renameable, A, a;
Renameable = {
setName: function(name){
this.name = name;
},
getName: function(){
var ref$;
return (ref$ = this.name) != null
? ref$
: this.id;
}
};
A = (function(){
A.displayName = 'A';
var prototype = A.prototype, constructor = A;
importAll$(prototype, arguments[0]);
function A(){
this.id = Math.random() * 1000;
}
return A;
}(Renameable));
a = new A;
a.getName();
a.setName('moo');
a.getName();
function importAll$(obj, src){
for (var key in src) obj[key] = src[key];
return obj;
}
要修改原型,可以使用简写::,如果要修改多个属性,则可以使用::=运算符。
class A
prop: 10
f: ->
@prop
a = new A
b = new A
a.f! #=> 10
A::prop = 6
a.f! #=> 6
b.f! #=> 6
A ::=
prop: 5
f: ->
@prop + 4
a.f! #=> 9
b.f! #=> 9
var A, a, b, ref$;
A = (function(){
A.displayName = 'A';
var prototype = A.prototype, constructor = A;
A.prototype.prop = 10;
A.prototype.f = function(){
return this.prop;
};
function A(){}
return A;
}());
a = new A;
b = new A;
a.f();
A.prototype.prop = 6;
a.f();
b.f();
ref$ = A.prototype;
ref$.prop = 5;
ref$.f = function(){
return this.prop + 4;
};
a.f();
b.f();
如果您不想支持旧版浏览器,并且希望使用Object.defineProperty,则可以使用以下简写
class Box
dimensions:~
-> @d
([width, height]) -> @d = "#{width}x#height"
b = new Box
b.dimensions = [10 5]
b.dimensions #=> '10x5'
var Box, b;
Box = (function(){
Box.displayName = 'Box';
var prototype = Box.prototype, constructor = Box;
Object.defineProperty(Box.prototype, 'dimensions', {
get: function(){
return this.d;
},
set: function(arg$){
var width, height;
width = arg$[0], height = arg$[1];
this.d = width + "x" + height;
},
configurable: true,
enumerable: true
});
function Box(){}
return Box;
}());
b = new Box;
b.dimensions = [10, 5];
b.dimensions;
=>更改为波浪箭头~>### ###更改为/* */undefined更改为void[x..y]更改为[x to y],并将[x...y]更改为[x til y]。如果您的范围向下,即从较大的数字到较小的数字,并且不明显(from和to不是字面量),则必须添加by -1,例如[x to -3 by -1]for i in [x..y]更改为for i from x to y,并将for i in [x...y]更改为for i from x til y(x for x in list)更改为[x for x in list]。任何您不希望返回列表的后缀循环,请更改为非后缀,例如,将increase x for x in list更改为for x in list then increase x。如果需要,您可以使用then的别名胖箭头=>来减少字符数.5更改为以零开头0.5/// ///更改为// //(args...) ->更改为前缀形式(...args) ->。() -> 仅变为 -> - 这是因为 () 始终是调用。class Item constructor: ->更改为在类体顶层简单地定义为函数,例如
class Item ->如果您的构造函数是外部函数,请使用特殊属性
constructor$$定义它。super更改为super ... - 这是因为super是对父函数的直接引用,而不是调用本身。&现在是.&.,>>现在是.>>.。x = 10 do -> x = 5必须使用
:=而不是=,因为这将在LiveScript中声明一个新的(遮蔽)变量。因此,如果要修改x,则上述代码需要是x = 10 do -> x := 5如果您想修改
x(x + y for x in [1, 2] for y in [3, 4]),则需要将其更改为常规(非后缀)嵌套循环,因为在CoffeeScript中结果是列表中的列表(示例的结果为[[4,5],[5,6]]),而结果是扁平化的(LiveScript中示例的结果为[4,5,5,6])。例如,更改result = (x + y for x in [1, 2] for y in [3, 4])到
result = for x in [1, 2]
for y in [3, 4]
x + y
以获得非扁平化的结果。it、that、fallthrough或otherwise的变量的名称。这些都是糟糕的变量名称,因此无论如何您都应该更改它们。从技术上讲,并非在所有情况下都需要这样做,但在所有情况下这样做会减少混淆。it用作没有参数定义的函数的隐式参数,例如reverse = -> it.reverse!。that指的是条件的值,例如that + 2 if (x + 10)/(y - 18),that == (x + 10)/(y-18)。fallthrough如果在case块的末尾使用,则使该块贯穿到下一个case。otherwise如果直接在case之后使用,则将该case变成默认值。"string"或'string'),例如text = "hi
there"
您将不得不像在CoffeeScript中一样更改它们,这将是"hi there",而LiveScript忽略换行符后的缩进,因此它将是"hi there"and、or以及带空格的.和?.会关闭隐式调用,因此您必须更改任何依赖于CoffeeScript不关闭调用的代码。例如,f a .g b or h c在CoffeeScript中将是f(a.g(b || h(c))),在LiveScript中将是f(a).g(b) || h(c)。您可以使用||代替or,使用&&代替and,因为这些版本不会关闭隐式调用。do的特殊情况函数字面量更改为使用let。例如,在CoffeeScript中do ($ = jQuery) -> $更改为let $ = jQuery $
do。例如,更改f a: b进入
f do a: b
`js code here`更改为``js code here``x . y,使其只在一侧或完全不带空格。现在,双空格点用于组合函数。a-b更改为带空格的a - b。a-1和1-b仍然可以使用。这是因为a-b在LiveScript中是一个有效的标识符,等效于其驼峰式写法aB。{a, b, ...c} = a: 1 b: 2 c: 3 x: 4现在将c设置为c: 3 x: 4,而不是c = {} <<< 3。(参见#941。)o{k: a.complex.expression}、{a xor b}、foo.bar = [a, b]:c、{...x ? y} = z现在都是错误。(参见#958了解原因。)a ?+= b现在表示a? && a += b,而不是a? || a += b(参见#969。)async函数和生成器(#978、#1063){a.b!c?key}(#958)process.argv.lsc属性,用于可靠地获取解释脚本参数(#1014)it参数(#899)for in词法分析错误(#923)match错误(#926)switch代码中不再有无法访问的break(#931)-ce、-aj选项组合(#993)for let ... when保护中的循环变量(#992)a[]b ++ c、a[]b ++= c(#542、#1028)-w选项运行时显示错误(#1015)for [] ... else(#1035)<[ ]>(#739)for arr case .. in(#1039)match中的_.member(#1025)let块中的yield和await(#1019、#1021、#1023)[a, ..., b, c, d] = [1 2 3]的LHS现在与[a, ...m, b, c, d]的行为相同。(参见#858。)
...。(参见 #863。)require 一个 .ls 文件时,会生成嵌入式源映射 (#786)require .json.ls 文件时,会进行适当的处理 (#884)ClassName.prototype.memberName = 模式进行赋值,这允许 JS 优化工具识别它们 (#853)[for x by y] (#837) 和 [.. for from i to j by k] (#859) 的支持.ls 文件时出错 (#830)livescript,因为 npm 不再允许发布对包含大写字母的包的更新-m,--map 标记的源映射支持-e,--eval 标记的命令行 JSON 处理。传入的 JSON 会绑定到 thislsc app.ls --flag 会导致错误)*<---const 标记的简写 -kby 关键字,例如 list[1 til 5 by 2]child_process.spawn 中已弃用的 customFds 用法return 和 throw 在管道方面的优先级。--require 选项,此选项在启动 REPL 时非常有用。还以类似于 require! 的方式使模块可访问。例如,--require './boom.js' 需要该文件并允许您使用 boom 访问它。require! 编译错误 - 现在会在应该出现错误时抛出错误require!,现在更像普通的解构了for let--no-header 选项,用于删除“Generated by…”标头livescript,只需使用 lscthat10 |> f _, 2 在编译时与 f 10, 2 相同--prelude/-d 标记现在仅用于 repl,在编译时不会添加 prelude.ls 包含!?、+++、where、undefined(void 的别名)、简短函数语法!。例如,(x) !-> x + x.json.ls 到 .jsonfor let++ 作为数组连接运算符,以替换 +++(现在已弃用)。++= 运算符以补充上述内容。[x + 1 for x in xs],您现在可以编写 [.. + 1 for xs],.. 是隐式值。请参阅 部分了解更多详细信息。(!x) -> ... 会转换为 (x) -> x = !x; ...。您可以使用它将参数转换为布尔值 (!!x) -> 或数字 (+x) ->。您还可以克隆对象,以便您不会修改原始对象:(^^x) ->。请参阅 部分了解更多信息。~~> 现在确实可以工作了,并且部分应用函数,例如 f _, 1 在第一次部分应用时就会绑定。+++ 数组连接运算符,请改用 ++。+++ 将在下一个主要 LiveScript 版本中删除。where 语句。请改用 let 和/或局部变量。where 将在下一个主要 LiveScript 版本中删除。undefined 作为 void 的别名。请改用 void。undefined 将在下一个主要 LiveScript 版本中删除。!? 不存在运算符。当后缀使用时,请改为否定存在运算符,例如,将 x!? 更改为 not x?。如果用作逻辑运算符,请改为使用 if 语句和存在运算符,例如,将 x !? f! 更改为 f! if x?。!? 将在下一个主要 LiveScript 版本中删除。f(x) = ... 类型的函数 - 请改用长箭头定义柯里化函数,例如 f = (x) --> ...。lsc 现在是 livescript 命令的别名,因为 livescript 比较长。想想“LiveScript Compiler”。[1 2 3]..push 3 ..shift!..sort!(+) .. 2 3
with 的用法,改为使用 let @ = x。with 可用于指定要级联的表达式的部分。例如x = with [1 2 3] ..push 3
try x catch 返回其捕获对象。by -1。constructor 的简写:@@x@y 和 x@@y 更改为使用 x{}y 和 x[]yres = for x to 2
for y to 3
"#x#y"
res #=> [ ['00', '01', '02', '03'], ['10', '11', '12', '13'], ['20', '21', '22', '23'] ]
如果需要扁平化结果,请改用推导式。为了方便起见,推导式现在可以多行。["#x#y" for x to 2
for y to 3]
#=> ['00', '01', '02', '03', '10', '11', '12', '13', '20', '21', '22', '23']
[[x + y for x to 2] for y to 3] #=> [ [0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5] ]现在按预期返回数组的数组。如果您依赖此行为,只需删除内部推导式的括号即可使其成为嵌套推导式。
require!,它接受对象、数组或字符串字面量,并创建一系列 require 语句。请参阅 文档。super 的功能,用于向类添加静态或实例方法。例如class A extends B A::meth -> super ... A.stat -> super ...
0。[to 3] #=> [0, 1, 2, 3] [til 3] #=> [0, 1, 2]
constructor$$: 定义。例如class A constructor$$: some-external-func
new,例如 new A ...aclass A
if condition
method: -> ...
else
method2: -> ...
for key of obj
(key): -> ...
do 操作,并且 do 语句不用作表达式,则该函数会保留其提升。例如f 1 #=> 1 do function f x x编译为
f(1);
function f(x){
return x;
} f();
[1 for til 3] #=> [1, 1, 1] for til 3 then f! [f! for from 1 to 5]
delete! 语句,类似于 JavaScript 中的 delete。这与 LiveScript 中的 delete 略有不同,后者如果用作表达式则会返回已删除的项。delete! x.y
``js code``for 循环和推导式索引是不可变的。如果您想修改索引,请使用 while 循环。此外,索引的最后一个值是它在循环中的最后一个值。catch 参数。in 在稀疏数组上起作用。--prelude/-d 标记适用于 replf(x) = x 现在使用 ~ 表示绑定函数,类似于命名函数,例如 ~f(x) = xf = ({x = 2, y = 3}) -> x + y,然后使用 f y: 4 应用+ 用于列表连接的重载(只需使用 +++).&.=where,类似于 let,但位于后面而不是前面 - 也允许嵌套赋值==)更改为 ~=,!~= 用于否定xor 运算符,异或 - 仅当一侧或另一侧为真时才为真x == /[ae]/g 等价于 /[ae]/g.exec(x) - 如果在if语句中使用,可以使用that获取结果。否定运算符则简单地使用test。(f or g) x 等价于 f(x) || g(x)list[1 to x] = [1 2 3]super$后缀命名,而不是__前缀。例如:ref$ 而不是 __refconstructor..=== - 实验性功能match语句 - 实验性功能& 为 .&.,>> 为 .>>.list[1 to x]class A extends Bf: ~>)绑定到实例,而不是类_占位符的函数部分应用with "cloneport",克隆头部并将尾部导入其中|>和反向管道<|的部分应用,并用作函数(?length)=、+=等。|>>管道运算符 - 现在使用普通管道和部分应用__作为switch语句中otherwise的别名--prelude或-d选项,以便在编译后的文件中自动包含prelude.ls--const或-k选项,以便像所有变量都是常量一样进行编译(obj.)&&作为arguments的别名,允许-> &0 + &1等。@@作为arguments的别名|>运算符的优先级,以允许在不使用括号的情况下赋值整个内容,而不仅仅是第一部分。implements,感谢Coco,例如:class Cow extends Animal implements Mooer,在类体中执行::<<< Mooer。(.length)和(.join \|) - 对于映射/过滤等很有用。&和+++的优先级|>编译~%%=有关更多详细信息,请参阅与Coco的差异。
您可以在此处找到完整的贡献者列表。该列表包括LiveScript及其前身的贡献者。
直接为LiveScript做出贡献的人包括George Zahariev、Satoshi Murakami、Joshua Weinstein、Josh Perez、Paul Miller、vendethiel、killdream、audreyt、clkao、viclib、dtinth、racklin、Raine Virta、Diggory Blake、Haspaker、synapsos、Rafael Belvederese、Kara Brightwell、Ryan Hendrickson、impinball、skovsgaard、Piotr Klibert、appedemic、Geza Kovacs、Isiah Meadows、Kevin Goslar、Kyle Kirby、Richard、Rob Loach、Viacheslav Lotsmanov、Vladislav Botvin、Yin Zhong、Allen Haim、Bartosz、dk00、Marek Pepke、Patrick Kettner。
感谢Niels Groot Obbink提供了livescript.org域名。
特别感谢Satoshi,因为这个项目是他项目Coco的一个分支,如果没有它,这个项目是不可能实现的。很高兴能够在他的优秀的Coco编译器基础上进行开发。
Fork LiveScript并进行更改。始终先编写测试(在/test目录中)。
查看包含的Makefile - 它包含所有可用的命令。
始终确保您可以make full - 即构建编译器本身。有用:git checkout -- lib && make full:清理您的lib并编译两次并进行测试。只有在所有测试通过后才发送拉取请求。一旦所有测试通过,重写任何需要重写的编译器,然后make full。使用make test-harmony使用生成器等测试节点的--harmony标志。
不要提交包含由make build-browser创建的构建浏览器文件(browser/livescript.js)的补丁。此文件仅在发布新版本之前构建。
自1.0.x版本以来,本节尚未更新
==编译为===,以及否定运算符。基本原理:大多数人更希望使用JavaScript的===而不是==,而且少打字更好,这使得它与CoffeeScript更相似,CoffeeScript将==编译为===,因此来自CoffeeScript的人需要更改的代码更少。is编译为===保持不变。in和of,使它们像CoffeeScript一样。In遍历值,of遍历键。基本原理:人们需要更改的CoffeeScript代码更少,他们已经习惯了,而且使用in检查一个值是否在一个数组中看起来很合理,使用of感觉很奇怪。~之外的所有位运算符都更改为用点号括起来,例如:&现在是.&.,>>是.>>.。位赋值运算符(例如:&=)已被删除。基本原理:人们很少一直使用位运算符,它们占用了一些宝贵的符号,这些符号可以用于其他用途。它们仍然可用,只是形式更长。~仍然存在。=>,使用_的管道运算符,已删除。释放=>(用于then别名),(|用作case的别名)。改为使用其他管道(|>)和部分应用。|是case(在switch中使用)的别名。基本原理:少打字,看起来不错。以Haskell的守卫为模型。=>是then的别名。基本原理:不会鼓励在if语句中使用它,因为它看起来有点奇怪 - 实际上是在switch语句中使用,与|结合使用,以创建一个简洁易懂的结构。基于Haskell在case表达式中使用->。otherwise和下划线_作为上下文关键字,在case或|之后使用时,使其成为默认语句。基本原理:与Haskell(otherwise)相同,下划线与Scala相同 - 并且更短。它允许| otherwise => 4 + 9,这与其余结构相符。->、~>、:或赋值之后,当它们后面跟着case标记(case或|)时,添加了隐式switch。基本原理:减少了输入量并提高了常见情况下使用switch的美观性,不会增加歧义。+++。例如:xs +++ ys为xs.concat(ys)。基本原理:少打字,更美观,受Haskell中++函数的启发(必须使用3个加号以避免与增量运算符产生歧义)。^现在是幂运算符**的别名。基本原理:它可用,并且在其他语言中使用。-->和~~>定义。有了它,您可以执行times = (x, y) --> x * y、timesTwo = times 2、timesTwo 4 #=> 8。如果您调用一个柯里化函数且没有参数,它会按原样调用自身,而不是返回自身(如果您想要自身,可以直接引用它)。基本原理:更像Haskell,有用的功能。add(x, y) = x + y == add = (x, y) --> x + y。您也可以在对象字面量和类定义中使用它,例如:add(x, y): x + y == add: (x, y) --> x + y。您也可以通过以感叹号开头来抑制两者中的返回,例如:!nothingness(params) = true不会返回任何内容。此外,您可以使用id@(param) = something来进行词法绑定this,这相当于id = (param) ~~> something(注意波浪号箭头)。如果您愿意,可以疯狂地执行以下操作:@!func@! = something,这是一个分配给this的函数,它不接受参数也不返回任何内容,同时在词法上绑定到this。使用此语法定义的所有函数都是柯里化的。基本原理:更美观,少打字,更像Haskell。obj ::= obj2作为obj::<<<obj2的别名。基本原理:似乎是预期的直观行为,看起来更简洁。yes / on作为true的别名,no / off作为false的别名。添加了undefined作为void的别名,并将isnt作为is not的别名。基本原理:简化从CoffeeScript到LiveScript的过渡,CoffeeScript具有所有这些特性。when作为case(和|)的别名。基本原理:简化从CoffeeScript的过渡。
x for x from 1 to 10 when x % 2 is 0。原因:简化从 CoffeeScript 的迁移,并在推导式中像其他语言(Haskell)一样使用守卫条件。else 作为默认值的功能。原因:简化从 CoffeeScript 的迁移。loop 作为 while true 的别名。原因:简化从 CoffeeScript 的迁移。|>,类似于 F#,val |> func 等价于 func(val)。与柯里化函数结合使用非常有用。原因:有用,如同在 F# 中。<|,类似于 F#:f <| x 等价于 f x。这比看起来更有用,可以帮助你避免使用括号。例如,对于返回一个将单词大写或小写的函数的 toCase 定义,使用 toCase \up <| \hello 而不是 toCase(\up) \hello。原因:有用,如上所述,如同在 F# 中。>> 和 <<。(f >> g) x 等价于 g(f(x)),而 (f << g) x 等价于 f(g(x))。原因:非常有用,尤其是在使用柯里化函数时。如同在 F#(以及 Haskell,在那里它是点操作符)中。%% 操作符(以及相应的 %%= 操作符),x %% y 等价于 (x % y + y) % y。例如,-3 % 4 == -3; -3 %% 4 == 1。原因:这是其他语言(如 Python 和 Ruby)中 % 操作符的行为方式。7r4 更改为 7~4。这是因为使用 r 会导致与数字注释产生歧义。例如,36rpm - 它是数字 36 带有数字注释 rpm 还是 pm 基数 36(922)?此外,现在接受任何数字作为基数,以便在该基数不是 2-36 时抛出更好的错误。原因:修复了歧义。[x to y/2] 而不是仅仅使用数字字面量。这具有移除裸范围的副作用,例如 2 to 5 没有包含括号(循环保持不变)。原因:范围中的表达式很有用,比裸范围更有用,裸范围的使用非常有限。也更接近 CoffeeScript,再次简化迁移。->、~> 或 = 结尾时继续执行。[x for x in list when x is \something])并删除了后缀循环(例如 something x for x in list)。推导式始终返回一个列表。嵌套列表推导式的行为正确,即最后一个 for 是最内层循环。原因:遵循 Haskell 和 Python。更一致的行为。更容易在脑海中处理。更直观。``js code here`` 而不是 `js code here`。原因:它很少需要;释放反引号用于中缀函数应用。3 `add` 2。原因:如同在 Haskell 中。这允许对其第二个参数进行部分应用,如操作符,例如 (`times` 2)。^ 更改为 ^^。原因:与幂操作符的部分应用区分开来。(+ 2) 返回一个将 2 加到其参数上的函数。也允许简单地使用 (*),它是一个将两个参数相乘的函数。(+x) 和 (-x) 仍然表示这些一元操作符的应用 - 操作符必须有空格才能表示该操作符的部分应用。在括号内不再允许使用长度星号 *(有时在设置动态键时使用),因为与部分应用的乘法操作符存在歧义。原因:很棒。如同在 Haskell 中。(not) 作为函数使用,将其组合等。原因:非常有用,如同在 Haskell 中。. 作为组合函数中 << 的别名。这禁止了 x . y 样式的属性访问。原因:如同在 Haskell 中。双空格属性访问不应该被使用。{[key, val * 2] for key, val of obj} 将返回一个对象,其所有值都是原始对象的两倍。数组字面量的第一部分被转换为键,第二部分被转换为值。原因:在处理对象时非常有用。现在可以将对象映射和过滤回对象。get-room 等价于 getRoom,encode-URI 等价于 encodeURI。原因:启用其他用户可能喜欢的不同风格。如同在 Lisp 系列语言中。(.length) 等价于 -> it.length,而 (.join \*) 等价于 -> it.join \*。(obj.) 等价于 -> obj[it]。原因:在映射、过滤等操作时很有用。with 操作符(“克隆端口”)。例如,personA = personB with name: \alice 等价于 personA = ^^personB <<< name: \alice。即,它克隆头部并将尾部导入到新对象中。personB 未修改。原因:创建新对象的一种非常好的方法。_ 是占位符。例如,f = add-three-numbers 1, _, 3 然后 f 2 #=> 6。可以多次使用,并且像柯里化函数一样,如果在没有参数的情况下调用,将执行,允许使用默认参数。原因:非常有用,当函数参数的顺序不理想时,可以使用柯里化版本。<- 更改为下划线 _。原因:与部分应用占位符相符。arguments 别名更改为 &,删除了 @@ 作为该别名。例如,-> &0 + &1。原因:更短 - 减少输入。-d, --prelude 选项,用于自动添加 prelude.ls。原因:使 prelude.ls 更易于使用。-k, --const 选项,用于编译为所有变量都是常量的情况。原因:一些来自所有值都是不可变的语言的用户可能会觉得这个功能不错。list[1 to x]。原因:有用。xor 操作符。原因:逻辑完整性。& 更改为 ..。原因:像其他语言中一样。