The LiveScript Book

 
 

The LiveScript Book

函数

定义函数是非常轻量级的。

1.(x, y) -> x + y
2.
3.-> # an empty function
4.
5.times = (x, y) ->
6. x * y
7.
8.# 多行函数表达式

1.var times;
2.(function(x, y) {
3. return x + y;
4.});
5.(function() {});
6.times = function(x, y) {
7. return x * y;
8.};

函数的定义是不是灰常灰常的短啊!

函数调用

你可以省略函数调用时的括号, 如何实际参数都是不可以调用,你甚至可以省略实参间的逗号,跟前面所讲的列表一个德行!

1.x = 4
2.Math.pow x, 3 # => 64
3.Math.pow 2 3 # => 8

当你调用一个无参函数时,只需在函数名后加个!即可,函数的链式调用也不用.链接。

1.f!
2.
3.[1 2 3].reverse!slice 1

1.f();
2.[1, 2, 3].reverse().slice(1);

andorxor.或者?.都会使得函数的实参列表收尾,这样就可以运行省掉括号后进行链式调用。

1.$ \h1 .find \a .text!

1.$('h1').find('a').text();

你可以用do去立即调用一个无参函数。

1.do -> 3 + 2

1.(function() {
2. return 3 + 2;
3.})();

do不用在表达式中的时候,你可以用do作用于一个命名函数,并且作用后这个函数还存在!

1.i = 0
2.
3.f 9 # => 9
4.
5.i # => 1
6.
7.do function f x
8. ++i
9. x
10.
11.i # => 2
12.
13.ff = do function gg x
14. x + 2

1.var i, ff;
2.i = 0;
3.f(9);
4.i;
5.
6.function f(x) {
7. ++i;
8. return x;
9.}
10.f();
11.i;
12.ff = (function() {
13. function gg(x) {
14. return x + 2;
15. }
16. return gg;
17.}())();

如果你要给函数传递一个对象,你应该使用do

1.func do
2. a: 1
3. b: 2

1.func({
2. a: 1,
3. b: 2
4.});

do让你可以做很多事情而不用加括号:

1.pow do
2. 1
3. 2
4.
5.h 1 do
6. a: 2
7. b: 5

1.pow(1, 2);
2.
3.h(1, {
4. a: 2,
5. b: 5
6.});

你可以采用中缀表达式类似的形式来进行函数调用。

1.add = (x, y) -> x + y
2.
3.3 `add` 4 # => 7

1.var add;
2.add = function(x, y) {
3. return x + y;
4.};
5.add(2, 4);

调用函数时使用...表示使用当前函数的实参去调用此函数。在调用super时,尤其有用。

1.f = (x, y) ->
2. x + y
3.
4.g = (a, b) ->
5. f ...
6.
7.g 3 4 # => 7

1.var f, g;
2.f = function(x, y) {
3. return x + y;
4.};
5.g = function(a, b) {
6. return f.apply(this, arguments);
7.};
8.g(3, 4);

参数

扩展的参数:

1.set-person-params = (
2. person
3. person.age
4. person.height
5.) -> person
6.
7.person = set-person-params {}, 21, 180cm
8.
9.# => Object {age: 21, height: 180}

1.var setPersonParams, person;
2.setPersonParams = function(person, age, height) {
3. person.age = age;
4. person.height = height;
5. return person;
6.};
7.person = setPersonParams({}, 21, 180);

扩展参数与this更配:

1.set-text = (@text) -> this

1.var setText;
2.setText = function(text) {
3. this.text = text;
4. return this;
5.};

你可以设置默认参数:

1.add = (x = 4, y = 3) -> x + y
2.
3.add 1 2 # => 3
4.add 1 # => 4
5.add! # => 7

1.var add;
2.add = function(x, y){
3. x == null && (x = 4);
4. y == null && (y = 3);
5. return x + y;
6.};
7.add(1, 2);
8.add(1);
9.add();

或者逻辑运算符(在参数中x = 2只是x ? 2的语法糖):

1.add = (x && 4, y || 3) -> x
2.
3.add 1 2 # => 6
4.add 2 0 # => 7

1.var add;
2.add = function(x, y) {
3. x && (x = 4);
4. y || (y = 3);
5. return x;
6.};
7.add(1, 2);
8.add(2, 0);

你也可以解构参数:

1.set-cords = ({x, y}) -> "#x, #y"
2.set-cords y: 2, x: 3 # => '3, 2'

1.var setCords;
2.setCords = function(arg$){
3. var x, y;
4. x = arg$.x, y = arg$.y;
5. return x + ", " + y;
6.};
7.setCords({
8. y: 2,
9. x: 3
10.});

你甚至可以设置参数析构时的默认参数:

1.set-cords = ({x = 1, y = 3} = {}) ->
2. "#x,#y"
3.set-cords y: 2, x: 3 # => '3,2'
4.set-cords x: 2 # => '2,3'
5.set-cords y: 7 # => '1,7'
6.set-cords! # => '1,3'

1.var setCords;
2.setCords = function(arg$) {
3. var ref$, x, ref1$, y;
4. ref$ = arg$ != null ? arg$ : {}, x = (ref1$ = ref$.x) != null ? ref1$ : 1, y = (ref1$ = ref$.y) != null ? ref1$ : 3;
5. return x + "," + y;
6.};
7.setCords({
8. y: 2,
9. x: 3
10.});
11.setCords({
12. x: 2
13.});
14.setCords({
15. y: 7
16.});
17.setCords();

你也可以在参数中使用...

1.f = (x, ...ys) -> x + ys.1
2.
3.f 1 2 3 4 # => 4

1.var f, slice$ = [].slice;
2.f = function(x) {
3. var ys;
4. ys = slice$.call(arguments, 1);
5. return x + ys[1];
6.};
7.f(1, 2, 3, 4);

你甚至可以在你的参数列表中使用一元运算符。你可以使用+!!来讲你的参数分别转换为数字和布尔类型,
或者使用克隆操作符^^来保证你对对象的任何操作都不会影响到原来的对象。

你依然可以使用扩展参数,例如:(!!x.x)->

1.f = (!!x) -> x
2.f 'truthy string' # => true
3.
4.g = (+x) -> x
5.g '' # => 0
6.
7.obj =
8. prop: 1
9.h = (^^x) ->
10. x.prop = 99
11. x
12.h obj
13.obj.prop # => 1

1.var f, g, obj, h;
2.f = function(x) {
3. x = !!x;
4. return x;
5.};
6.f('truthy string');
7.g = function(x) {
8. x = +x;
9. return x;
10.};
11.g('');
12.obj = {
13. prop: 1
14.};
15.h = function(x) {
16. x = clone$(x);
17. x.prop = 99;
18. return x;
19.};
20.h(obj);
21.obj.prop;
22.
23.function clone$(it) {
24. function fun() {}
25. fun.prototype = it;
26. return new fun;
27.}

柯里化

柯里化函数是非常强大的。本质上来说,当一个函数被调用时,实参个数少于形参的个数,就会返回一个偏应用函数。也就是说,
返回的函数的形参是那些你刚才没给实参对应的形参,已给的实参会自动绑定。在 LiveScript 中进行函数柯里化使用长箭头。也许一个例子更能说清问题。

1.times = (x, y) --> x * y
2.times 2, 3 # => 6 (normal use works as expected)
3.double = times 2
4.double 5 # => 10

1.var times, double;
2.times = curry$(function(x, y) {
3. return x * y;
4.});
5.times(2, 3);
6.double = times(2);
7.double(5);
8.
9.function curry$(f, bound) {
10. var context,
11. _curry = function(args) {
12. return f.length > 1 ? function() {
13. var params = args ? args.concat() : [];
14. context = bound ? context || this : this;
15. return params.push.apply(params, arguments) <
16. f.length && arguments.length ?
17. _curry.call(context, params) : f.apply(context, params);
18. } : f;
19. };
20. return _curry();
21.}

你可以使用~~>定义柯里化的限界函数:

如果你不带参数的调用一个柯里化的函数,你可以设置它的默认参数。

1.f = (x = 5, y = 10) --> x + y
2.
3.f! # => 15
4.
5.g = f 20
6.g 7 # => 27
7.g! # => 30

1.var f, g;
2.f = curry$(function(x, y) {
3. x == null && (x = 5);
4. y == null && (y = 10);
5. return x + y;
6.});
7.f();
8.g = f(20);
9.g(7);
10.g();
11.
12.function curry$(f, bound) {
13. var context,
14. _curry = function(args) {
15. return f.length > 1 ? function() {
16. var params = args ? args.concat() : [];
17. context = bound ? context || this : this;
18. return params.push.apply(params, arguments) <
19. f.length && arguments.length ?
20. _curry.call(context, params) : f.apply(context, params);
21. } : f;
22. };
23. return _curry();
24.}

命名函数

你可以通过创建命名函数来使得这些函数作用域得到提升。对在文件尾部而非顶部定义效用函数是非常有用的。
命名函数是不可修改的,也不能被重新定义!

1.util!     # => '可以在定义位置前使用'
2.
3.util2! # => 2
4.
5.function util
6. '可以在定义位置前使用'
7.function util2 then 2

1.util();
2.util2();
3.
4.function util() {
5. return '可以在定义位置前使用';
6.}
7.
8.function util2() {
9. return 2;
10.}

通过在命名函数前置~使得命名函数成为一个限定函数。

1.~function add x, y
2. @result = x + y

1.var this$ = this;
2.
3.function add(x, y) {
4. return this$.result = x + y;
5.}

你可以通过在命名函数前置!来取消自动返回:

1.util!     # =>
2.!function util x then x

1.util();
2.
3.function util(x) {
4. x;
5.}

你可以组合使用~!来使得命名函数按你想的那样限定且无返回值。

限定函数

使用~>来定义限定函数,使用~~>来定义柯里化的限定函数。限定函数词法绑定了this
并不像平常那样动态绑定。也就是说,无论在什么上下文中调用此函数,函数体内的this都会始终保持它定义时所指的this

1.obj = new
2. @x = 10
3. @normal = -> @x
4. @bound = ~> @x
5.
6.obj2 = x: 5
7.obj2.normal = obj.normal
8.obj2.bound = obj.bound
9.
10.obj2.normal! # => 5
11.obj2.bound! # => 10

1.var obj, obj2;
2.obj = new function() {
3. var this$ = this;
4. this.x = 10;
5. this.normal = function() {
6. return this.x;
7. };
8. this.bound = function() {
9. return this$.x;
10. };
11.};
12.obj2 = {
13. x: 5
14.};
15.obj2.normal = obj.normal;
16.obj2.bound = obj.bound;
17.obj2.normal();
18.obj2.bound();

let, new

let(function(a){...}.call(this, b))的缩写。

1.let x = 2
2. console.log x

1.(function(x) {
2. console.log(x);
3.}.call(this, 2));

你也可以使用let定义this(也即@):

1.x = let @ = a: 1, b: 2
2. @b ^ 3
3.x # => 8

1.var x;
2.x = (function() {
3. return Math.pow(this.b, 3);
4.}.call({
5. a: 1,
6. b: 2
7.}));
8.x;

新的上下文:

1.dog = new
2. @name = \spot
3. @mutt = true
4.
5.# => Object {name: "spot", mutt: true}

1.var dog;
2.dog = new function() {
3. this.name = 'spot';
4. this.mutt = true;
5.};

函数访问|调用的简写

对于像map以及filter等这些高阶函数,这个就非常有用了。

(.prop)(it) -> it.prop的简写。

译注:所涉及到的mapfilterhead以及revers函数均来自prelude.ls

1.map (.length), <[ hello there you ]>
2.# => [5, 5, 3]
3.
4.filter (.length < 4), <[ hello there you ]>
5.# => ['you']

1.map(function(it) {
2. return it.length;
3.}, ['hello', 'there', 'you']);
4.filter(function(it) {
5. return it.length < 4;
6.}, ['hello', 'there', 'you']);

你也可以用这个去调用方法:

1.map (.join \|), [[1 2 3], [7 8 9]]
2.# => ['1|2|3', '7|8|9']

1.map(function(it) {
2. return it.join('|');
3.}, [
4. [1, 2, 3],
5. [7, 8, 9]
6.]);

(obj.)(it) -> obj[it]的简写:

1.obj =
2. one: 1
3. two: 2
4. three: 3
5.
6.map (obj.), <[ one three ]>
7.# => [1, 3]

1.var obj;
2.obj = {
3. one: 1,
4. two: 2,
5. three: 3
6.};
7.map(function(it) {
8. return obj[it];
9.}, ['one', 'three']);

回调函数

回调函数灰常灰常的有用,它允许回调的非嵌套。用向左的箭头进行定义,其余的跟普通的函数一样的,用<~定义限定函数,
<~~<--分别定义柯里化的限定函数和柯里化的普通函数,用<-!来取消自动返回。

1.<- f
2.alert \boom

1.f(function() {
2. return alert('boom');
3.});

可以设置函数的参数,你还可以指定回调函数所在形参的位置。

1.x <- map _, [1 to 3]
2.x * 2
3.# => [2, 4, 6]

1.map(function(x) {
2. return x * 2;
3.}, [1, 2, 3]);

如果你的回调函数之后还包含其他代码,你可以使用do语句,来将他们别开来。

1.do
2. data <-! $.get \ajaxtest
3. $ '.result' .html data
4. processed <-! $.get \ajaxprocess, data, _
5. $ '.result' .append processed
6.
7.alert \hi

1.$.get('ajaxtest', function(data) {
2. $('.result').html(data);
3. $.get('ajaxprocess', data, function(processed) {
4. $('.result').append(processed);
5. });
6.});
7.alert('hi');

偏函数应用

你可以使用下划线作_作为一个占位符,进行偏函数应用。有时候,你要处理的函数并没有柯里化,或者它的形参列表顺序并不理想,在这种情况下,偏函数就变得特别有用。

1.filter-nums = filter _, [1 to 5]
2.
3.filter-nums even # => [2, 4]
4.filter-nums odd # => [1, 3, 5]
5.filter-nums (< 5) # => [1, 2]

1.var filterNums, slice$ = [].slice;
2.filterNums = partialize$.apply(this, [filter, [void 8, [1, 2, 3, 4, 5]],
3. [0]
4.]);
5.filterNums(even);
6.filterNums(odd);
7.filterNums((function(it) {
8. return it < 5;
9.}));
10.
11.function partialize$(f, args, where) {
12. var context = this;
13. return function() {
14. var params = slice$.call(arguments),
15. i,
16. len = params.length,
17. wlen = where.length,
18. ta = args ? args.concat() : [],
19. tw = where ? where.concat() : [];
20. for (i = 0; i < len; ++i) {
21. ta[tw[0]] = params[i];
22. tw.shift();
23. }
24. return len < wlen && len ?
25. partialize$.apply(context, [f, ta, tw]) : f.apply(context, ta);
26. };
27.}

如果你不带参数调用一个偏函数,那么它将返回它自己,允许你使用默认参数。

在使用管道的时候偏函数也非常有用,尤其是在你的参数列表不够优雅并且没有柯里化。

1.[1 2 3]
2.|> _.map _, (* 2)
3.|> _.reduce _, (+), 0
4.# => 12

1._.reduce(_.map([1, 2, 3], (function(it) {
2. return it * 2;
3.})), curry$(function(x$, y$) {
4. return x$ + y$;
5.}), 0);
6.
7.function curry$(f, bound) {
8. var context,
9. _curry = function(args) {
10. return f.length > 1 ? function() {
11. var params = args ? args.concat() : [];
12. context = bound ? context || this : this;
13. return params.push.apply(params, arguments) <
14. f.length && arguments.length ?
15. _curry.call(context, params) : f.apply(context, params);
16. } : f;
17. };
18. return _curry();
19.}

形参

如果你只有一个参数,你没必要去定义参数,你可以使用it去访问参数。

1.f = -> it + 2
2.f 3 # => 5

1.var f;
2.f = function(it) {
3. return it + 2;
4.};
5.f(3);

使用&来访问arguments对象,第一个参数是&0,第二个是&1,以此类推。&就是arguments

1.add-three-numbers = -> &0 + &1 + &1
2.add-three-number 1 2 3 # => 6

1.var addThreeNumbers;
2.addThreeNumbers = function() {
3. return arguments[0] + arguments[1] + arguments[1];
4.};
5.addThreeNumber(1, 2, 3);

注意 在这种情况下,柯里化可能不会发生,因为arguments声明的参数个数为0

 

LiveScript 函数的更多相关文章

  1. PHP清理跨站XSS xss_clean 函数 整理自codeigniter Security

    PHP清理跨站XSS xss_clean 函数 整理自codeigniter Security 由Security Class 改编成函数xss_clean 单文件直接调用.BY吠品. //来自cod ...

  2. js 函数声明方式以及javascript的历史

    1.function  xx(){} 2.匿名方式   window.onload=function(){dslfjdslfkjdslf}; 3.动态方式  var demo=new Function ...

  3. 更优雅的方式: JavaScript 中顺序执行异步函数

    火于异步 1995年,当时最流行的浏览器--网景中开始运行 JavaScript (最初称为 LiveScript). 1996年,微软发布了 JScript 兼容 JavaScript.随着网景.微 ...

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

    The LiveScript Book     The LiveScript Book Generators and Yield 你可以在你的 LiveScript 代码中使用 Ecmascript ...

  5. LiveScript 操作符

    The LiveScript Book     The LiveScript Book 操作符 数字 标准的数学操作符: 1.1 + 2 # => 32.3 - 4 # => -13.6 ...

  6. 初识LiveScript

        The LiveScript Book 邂逅 LiveScript 就像很多现代化的语言一样,LiveScript 使用缩进来表示语句块,使用换行取代分号来表示一个语句的结束 (如果你想要一行 ...

  7. JavaScript 基础(数据类型、函数、流程控制、对象)

    一.JavaScript概述 1.1 JavaScript的历史 1992年Nombas开发出C-minus-minus(C--)的嵌入式脚本语言(最初绑定在CEnvi软件中).后将其改名Script ...

  8. Python 小而美的函数

    python提供了一些有趣且实用的函数,如any all zip,这些函数能够大幅简化我们得代码,可以更优雅的处理可迭代的对象,同时使用的时候也得注意一些情况   any any(iterable) ...

  9. 探究javascript对象和数组的异同,及函数变量缓存技巧

    javascript中最经典也最受非议的一句话就是:javascript中一切皆是对象.这篇重点要提到的,就是任何jser都不陌生的Object和Array. 有段时间曾经很诧异,到底两种数据类型用来 ...

随机推荐

  1. linux命令之文本查看

    vi掌握练习: 英文文档,相同的单词复制粘贴光标移动编辑等操作: cat:显示文件所有内容,小文件查看时使用. 缺点:文件大时不方便查看,文件很大时,会抢占系统资源,会出现命令崩溃. [zyj@loc ...

  2. ACM TOMM 2017最佳论文:让AI接手繁杂专业的图文排版设计工作

    编者按:你是否曾经为如何创作和编辑一篇图文并茂.排版精美的文章而烦恼?或是为缺乏艺术灵感和设计思路而痛苦?AI技术能否在艺术设计中帮助到我们?今天我们为大家介绍的这篇论文,“Automatic Gen ...

  3. python os,sys模块的使用

    首先,os模块是用来与操作系统进行交互的模块,可以对操作系统上的一些东西进行操作 而sys是用来对解释器进行一些操作的 一.os os.getcwd() 获取当前工作目录,即当前python脚本工作的 ...

  4. xampp默认配置拿shell

    xampp默认配置拿shell 首先我们先来科普一下xampp(Apache+MySQL+PHP+PERL)是一个功能强大的建 XAMPP 软件站集成软件包 是一个易于安装且包含 MySQL.PHP ...

  5. git 作成

    Git global setup git config --global user.name "高 文龍" git config --global user.email " ...

  6. linux虚拟机配置网络

    第一步.网络模式设置为桥接模式   第二步.设置ip和掩码 vim /etc/sysconfig/network-scripts/ifcfg-ens33 ens33为当前机器的网卡名称  在文件尾部添 ...

  7. Ping 命令的执行过程和应用协议

    1. ICMP是“Internet Control Message Ptotocol”的缩写.它是TCP/IP协议族的一个子协议,用于在IP主机.路由器之间传递控制消息. 控制消息是指网络通不通.主机 ...

  8. 【上下界网络流】bzoj2502: 清理雪道

    模型:无源汇有上下界可行流 LJN:模板题吧 Description        滑雪场坐落在FJ省西北部的若干座山上. 从空中鸟瞰,滑雪场可以看作一个有向无环图,每条弧代表一个斜坡(即雪道),弧的 ...

  9. Flask-数据与路由

    数据 图书数据库的地址 # 基地址 http://t.yushu.im # 关键字搜索 http://t.yushu.im/v2/book/search?q={}&start={}&c ...

  10. unbuntu14下Qt4.8 和MySQL连接问题 QSqlDatabase: QMYSQL driver not loaded QSqlDatabase: available drivers: QSQLITE

    使用 QSqlDatabase::addDatabase创建数据库时 会报错: QSqlDatabase: QMYSQL driver not loaded QSqlDatabase: availab ...