• LiveScript 函数


    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 oom

    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

     
  • 相关阅读:
    (转)投票系统,更改ip刷票
    图像判断(转)
    第06组 Alpha事后诸葛亮
    第06组 Alpha冲刺(6/6)
    2019 SDN上机第4次作业
    第06组 Alpha冲刺(5/6)
    第06组 Alpha冲刺(4/6)
    第06组 Alpha冲刺(3/6)
    第06组 Alpha冲刺(2/6)
    2019 SDN上机第3次作业
  • 原文地址:https://www.cnblogs.com/crackpotisback/p/5177534.html
Copyright © 2020-2023  润新知