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. Android studio 3.1.1 找不到DDMS

    先找到AndroidStudio配置的SDK路径: 在SDK的/tools/路径下[就是和配置ADB一样的路径]有个monitor.bat 的批处理文件: 鼠标连续点击两下monitor.bat这个批 ...

  2. zabbix2升级zabbix3

    1.停服zabbix2,停服数据库/etc/init.d/zabbix_server stop/etc/init.d/mysqld stop 2.物理备份数据库cd /var/lib/mysql/ta ...

  3. Python3自动化学习地址

    w3社区https://www.w3cschool.cn/python/ 易百教程https://www.yiibai.com/ http://www.cnblogs.com/yangxia-test ...

  4. python面试笔试题汇总

    Python面试攻略(嗨谈篇) 110道python面试笔试题汇总,你能答对几道? Python 面试问答 Top 25 2018 年最常见的 Python 面试题 & 答案

  5. Ajax的原理及Django上传组件

    title: Ajax的原理及Django上传组件 tags: Django --- Ajax的原理及Django上传组件 Ajax的原理 ajax 是异步JavaScript和xml ajax就是向 ...

  6. laydate时间控件绑定回调事件

    onclick="laydate({istime: true, format: 'YYYY-MM-DD',choose:checkDate});" //回调函数内容 functio ...

  7. Linux学习日记:第一天

    一,登录Linux Login:test Password:123456 Last Login:Wed Dec 3 22:40:02 on tty1 test@ubuntu: startx    进入 ...

  8. HomeKit开发(一)

    需求:因为公司的生产硬件需要进入苹果的HomeKit市场,因此需要一款供苹果审核的APP(功能:苹果的家庭软件的功能+公司的硬件支持的功能特有功能)需求驱动开发:最近做了一款苹果HomeKit的软件 ...

  9. iOS项目工程及目录结构

    做过一些iOS的项目,不同项目的沉淀没有积累到一起,目录的管理都在后期随着人员的增加越来越混乱,因此在这里做一些梳理,希望达到两个目的. 一套相对通用的目录结构,作为后续项目的模版. 积累相应的基础库 ...

  10. Mutations-freecodecamp算法题目

    Mutations(比较字符串) 要求 如果数组第一个字符串元素包含了第二个字符串元素的所有字符,函数返回true. 不用考虑大小写和字符顺序 思路 将数组中的两个字符串小写化 将第二个数组元素(第二 ...