你可能不知道 LiveScript 的 10 个强大功能

2012年12月3日 - Vendethiel

以下文章由 Vendethiel 撰写。你也可以提交客座文章,只需发送一个 pull request 即可。

LiveScript 拥有许多你可能不知道的技巧和窍门。

在这篇博文中,我们将了解如何利用它们!

操作符重载

LiveScript 为数组和字符串提供了一些基本的操作符重载功能。

# when the left one is an array literal
['a' 'b'] * 2 # array repetition
# when the right one is a string literal
<[ foo bar ]> * ', ' # array joining

# or when the left one is a string
y = 2
'z' * y # string repetition
words = text / ' ' # string division

# or even when the right one is either a string or a regexp
unspaced = text - /\s+/
[\a to \e] * '' - 'b'
var y, words, unspaced, split$ = ''.split, replace$ = ''.replace;
['a', 'b', 'a', 'b'];
['foo', 'bar'].join(', ');


y = 2;
repeatString$('z', y);
words = split$.call(text, ' ');


unspaced = replace$.call(text, /\s+/, '');
["a", "b", "c", "d", "e"].join('').replace('b', '');
function repeatString$(str, n){
  for (var r = ''; n > 0; (n >>= 1) && (str += str)) if (n & 1) r += str;
  return r;
}

Heregex 动态标记

你可以使用 ? 动态标记 Heregex。

在这种情况下,将使用最后的插值。

//
  my?
  #normal
  #{[interpolation]}
  #flag
//?
RegExp('my?' + normal + [interpolation], flag);

使用 new 创建上下文

你可以单独使用 new 来创建一个新的上下文。

paul = new
  @name = 'paul'
  @age = 25

# LiveScript has real object comprehensions
flip = (obj) -> new
  for own k, v of obj then @[v] = k
var paul, flip;
paul = new function(){
  this.name = 'paul';
  return this.age = 25;
};
flip = function(obj){
  return new function(){
    var k, ref$, v, own$ = {}.hasOwnProperty, results$ = [];
    for (k in ref$ = obj) if (own$.call(ref$, k)) {
      v = ref$[k];
      results$.push(this[v] = k);
    }
    return results$;
  };
};

动态键

JavaScript 不允许动态键,因为它们不像 JSON 中那样用引号括起来。

使用 LiveScript,你可以使用圆括号来获取动态属性。

foo = 'key'
bar = {(foo): 5, "dyna#foo": 6} #=> {'key': 5, 'dynakey': 6}

# in destructuring
{(+* .>>. 1): middle} = [1 to 7] # middle = 4
var foo, bar, ref$, middle;
foo = 'key';
bar = (ref$ = {}, ref$[foo] = 5, ref$["dyna" + foo] = 6, ref$);

middle = [1, 2, 3, 4, 5, 6, 7][+[1, 2, 3, 4, 5, 6, 7].length >> 1];

解构默认值

在解构时,你可能需要默认值。使用 LiveScript,你可以使用任何逻辑运算符、存在运算符(别名为 =),甚至可以像在其他任何情况下一样将它们链接起来。

{username ? 'root', password || '', secure && 'https' || 'http'} = config<[ USERNAME PASSWORD SECURE ]>
var ref$, username, ref1$, password, secure;
ref$ = [config['USERNAME'], config['PASSWORD'], config['SECURE']],
username = (ref1$ = ref$.username) != null ? ref1$ : 'root', password = ref$.password || '',
secure = ref$.secure && 'https' || 'http';

扩展参数

在 LiveScript 中,参数接受的不仅仅是简单的字面量。你可以分配属性,还可以做更复杂的事情,例如半自动激活。

class Person
  # defaults @name to [], and assigns the first element
  set-first-name: (@[]names.0) ->
  
  # defaults @name to [], and adds the element (* being the array's length)
  add-name: (@[]names[*]) ->
  
  # defaults @hair to {}, and assigns color
  set-hair-color: (@{}hair.color) ->







p = new Person
p.hair # undefined
p.set-hair-color "#8b0000"
p.hair.color # "#8b0000"

p.names # undefined
p.add-name 'George'
p.add-name 'Jean'
p.names # ["George", "Jean"]
p.set-first-name "Paul"
p.names # ["Paul", "Jean"]
var Person, p;
Person = (function(){
  Person.displayName = 'Person';
  var prototype = Person.prototype, constructor = Person;
  prototype.setFirstName = function($0){
    (this.names || (this.names = []))[0] = $0;
  };
  prototype.addName = function(arg$){
    var ref$;
    (ref$ = this.names || (this.names = []))[ref$.length] = arg$;
  };
  prototype.setHairColor = function(color){
    (this.hair || (this.hair = {})).color = color;
  };
  function Person(){}
  return Person;
}());
p = new Person;
p.hair;
p.setHairColor("#8b0000");
p.hair.color;

p.names;
p.addName('George');
p.addName('Jean');
p.names;
p.setFirstName("Paul");
p.names;

数组和对象展开

数组和对象可以以多种方式进行切片。你可能知道 a[0 1],我们也看到了 a<[foo bar]>,但你还可以做更多的事情。例如,你可以使用展开符。

posts['op' ...'replies'] = thread



# even with objects
extended = {...base, +extended}
var the, end, extended, ref$, slice$ = [].slice;
posts['op'] = thread[0], posts['replies'] = slice$.call(thread, 1);

extended = (ref$ = {}, import$(ref$, base), ref$.extended = true, ref$);
function import$(obj, src){
  var own = {}.hasOwnProperty;
  for (var key in src) if (own.call(src, key)) obj[key] = src[key];
  return obj;
}

低优先级反管道和 do

低优先级反管道可以用于函数求值,不仅可以用来在没有圆括号的情况下链接参数,而且还可以做更多的事情,例如允许你使用 do。

# basic backpipe usage
toCase \up <| \hello

# let's say that, if we have no page, we need to create an un element
# with a li element containing 1
pages.appendChild <| do
  node 'ul' className: 'ui-pagination'
    ..appendChild node 'li' innerHTML: '1'
var x$;
toCase('up')('hello');




pages.appendChild((x$ = node('ul', {
  className: 'ui-pagination'
}), x$.appendChild(node('li', {
  innerHTML: '1'
})), x$));

Do 可以用来改变顺序或提供更多空间来编写一些复杂的表达式。

td = node 'td' class: 'informations' innerHTML: do
  i18n.get-translation 'informations' .format-for @user





# use do and backcall
promises =
  value: do
    <- $.get 'a'
var td, promises;
td = node('td', {
  'class': 'informations',
  dataType: 'info',
  innerHTML: i18n.getTranslation('informations').formatFor(this.user)
});

promises = {
  value: $.get('a', function(){})
};

Thisplat

你经常需要将对函数的调用延迟,并保持相同的上下文和参数。你可以为此使用 thisplat。

call = -> call-instead ...
var call;
call = function(){
  return callInstead.apply(this, arguments);
};

标签

如果需要使用标签,可以使用块或表达式。

# labeling a function gives it a name
:refresh let
    wait '10s' !->
      console.log 'timeout !'
      refresh!



# label a for
:serie for i to 100
  for j to 100
    if (Math.floor Math.random! * 11) > 8
      continue serie

    console.log "#i:#j"
var i$, i, j$, j;
(function refresh(){
  wait('10s', function(){
    console.log('timeout !');
    refresh();
  });
}.call(this));

serie: for (i$ = 0; i$ <= 100; ++i$) {
  i = i$;
  for (j$ = 0; j$ <= 100; ++j$) {
    j = j$;
    if (Math.floor(Math.random() * 11) > 8) {
      continue serie;
    }
    console.log(i + ":" + j);
  }
}

无操作字面量和展开

你可以使用 , 表示无操作字面量。

以及展开数组或参数。

[a, b, c, ,, d] = foo
[the, ..., end] = my-friend

a = (, b) -> b # b is a's second argument




# forces the closure's argument list to be empty
test 'it works' (...) ->
 it # it wasn't shadowed
var a, b, c, d, the, end;
a = foo[0], b = foo[1], c = foo[2], d = foo[5];
the = myFriend[0], end = myFriend[myFriend.length - 1];

a = function(arg$, b){
  return b;
};

test('it works', function(){
  return it;
});

有关 LiveScript 的更多信息,请查看 LiveScript 网站


有关 LiveScript 和 prelude.ls 的更多信息,请

评论由 Disqus 提供支持