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. ArcGIS for Server内置JS Viewer的离线部署和配置

    很多情况下,在地图服务发布完毕后,我们往往利用 ArcGIS for Server内置的 JS Viewer来查看和检测所发布的地图服务是否满足我们的要求.具体操作如下: 点击开始 -> 所有程 ...

  2. Yii2.0数据库缓存依赖发布的使用理解

    对于产品中经常需要生成一些缓存类的东西,比如系统基础配置,商品分类等,每次修改调整后都要手动进行缓存发布,是不是非常麻烦!这时候Yii2.0的缓存依赖发布就起到至关重要的作用了!现将主要的使用流程介绍 ...

  3. 【Python图像特征的音乐序列生成】关于图像特征的描述词

    查阅了很久的资料,决定依据Yoshida的<Image retrieval system using impression words>这篇论文里的词语来定义. Yoshida 等的 Ar ...

  4. 会写网页 就会写手机APP #2-- 范例修正 , Hybrid Mobile Apps for ASP.NET Developers (Apache Cordova)

    原文出处:会写网页 就会写手机APP #2-- 范例修正 , Hybrid Mobile Apps for ASP.NET Developers (Apache Cordova) 这是我的文章备份  ...

  5. TIF转JPG

    public void TifToJpg(string tifPath, string tifName) { try { //找到后缀为TIF的图像,如果没有,就catch退出 int len = t ...

  6. tpcc-mysql的安装和使用

    tpcc-mysql介绍 TPC(Tracsaction Processing Performance Council) 事务处理性能协会是一个评价大型数据库系统软硬件性能的非盈利的组织,TPC-C是 ...

  7. halt, reboot, poweroff - 中止系统运行

    SYNOPSIS /sbin/halt [-n] [-w] [-d] [-f] [-i] [-p] /sbin/reboot [-n] [-w] [-d] [-f] [-i] /sbin/powero ...

  8. python 与 json

    +-------------------+---------------+    | Python            | JSON          |    +================= ...

  9. 谈谈TCP的四次挥手

    “挥手”是为了终止连接,TCP四次挥手的流程图如下: (在socket编程中,可以由客户端或服务端进行close操作来进行) 下面的图是由客户端主动关闭连接 MSL是什么?最长报文段寿命 ------ ...

  10. PAT (Basic Level) Practise (中文)- 1015. 德才论 (25)

    http://www.patest.cn/contests/pat-b-practise/1015 宋代史学家司马光在<资治通鉴>中有一段著名的“德才论”:“是故才德全尽谓之圣人,才德兼亡 ...