博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
LiveScript 函数
阅读量:4657 次
发布时间:2019-06-09

本文共 11673 字,大约阅读时间需要 38 分钟。

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

 

转载于:https://www.cnblogs.com/crackpotisback/p/5177534.html

你可能感兴趣的文章
Spring cloud 基础
查看>>
游戏开发Unity渲染场景光照性能优化 ShaderLOD
查看>>
java中构造方法的使用
查看>>
使用Expression动态创建lambda表达式
查看>>
MapReduce
查看>>
找工作——JVM内存管理
查看>>
【Flask】在Flask中使用logger
查看>>
好系统重装助手教你如何让win10系统快速开机
查看>>
linux开机启动
查看>>
BZOJ 1101 [POI2007]Zap 【莫比乌斯反演】
查看>>
SQL Server-The target principal name is incorrect. Cannot generate SSPI context
查看>>
AS3全局与局部坐标转换
查看>>
Java内部类详解
查看>>
初识Twisted(一)
查看>>
linux 软件安装篇
查看>>
Sql server数据库大小写敏感设置
查看>>
JAVA多线程-内存模型、三大特性、线程池
查看>>
RxJS速成 (下)
查看>>
无锁栈与无锁队列
查看>>
微信开发第8章 通过accesstoken将长连接转换为短链接
查看>>