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. wordpress安装后首页无法进入 The file 'wp-config.php' already exists

    问题是缓存导致,具体还没研究是怎么产生的缓存.chrome浏览器解决方法: 1. 网址后面加参数进入网站 2. 打开控制台-network 3. 刷新页面 4. 控制台-network,右键请求的文件 ...

  2. Object-C反射读取实体属性和值

    举例: 首先定义TestModel如下: @interface TestModel : NSObject @property (nonatomic, strong) NSString *name; @ ...

  3. 数据库迁移后报错提示MySQL Error:Can''t find file errno: 13 - Permission denied的解决方法

    用户MYSQL数据库迁移后,遇到报错MySQL Error:Can't find file (errno: 13 - Permission denied)使用以下指令重新设置所有者和权限,依然不能解决 ...

  4. Protocol Buffer学习教程之编译器与类文件(三)

    Protocol Buffer学习教程之编译器与类文件(三) 1. 概述 在前面两篇中,介绍了Protobuf的基本概念.应用场景.与protobuf的语法等.在此篇中将介绍如何自己编译protobu ...

  5. javaSe-常用的类之Calender

    Calendar是java中常用的类,比data类使用更加方便,更能更加强大,好吧多的不用你说了,直接上代码 import java.util.Calendar;//需要引进的包 public cla ...

  6. jsp另外五大内置对象之-exception

    //有异常的页面 <%@ page language="java" contentType="text/html; charset=utf-8" page ...

  7. codeforce Gym 100342J Triatrip (bitset)

    傻逼题,但是为什么别人的O(n^3)不会T?只是因为用了bitset优化... 附上一张bitset基本操作的表 #include<bits/stdc++.h> using namespa ...

  8. Ubuntu18.04偏好设置

    以下只是我个人的一些偏好设置,会持续更新 一.安装中文输入法和换用中文界面 Ubuntu18.04下安装搜狗输入法 Ubuntu18.04如何从英文界面更改为中文界面 二.更改系统自带设置 1.设置- ...

  9. GIT分布式版本控制器的前后今生

    Git的入门与安装 GIT基础操作 GIT的分支应用 GITLAB应用 gitlab与pycharm应用 GITHUB使用

  10. vue props 传入对象Object,如果外层更改属性,默认里面是不更新,需要使用 this.$set(this.datese1, 'xsfaDateYear1', '')

    vue props 传入对象Object,如果外层更改属性,默认里面是不更新,需要使用 this.$set(this.datese1, 'xsfaDateYear1', '')