函数

Stylus 具有强大的内置于语言层面的函数定义。函数定义与混入(mixins)一致,但是却可以返回值。

返回值

一个很简单的例子:创建一个两数相加的函数。

add(a, b)
  a + b

我们可以将上述函数用在条件表达式中、作为属性值等等。

 body 
   padding add(10px, 5)

输出为:

 body {
   padding: 15px;
 }

默认参数

可选参数可以赋值一个表达式。在 Stylus 中,我们甚至可以使用参数列表中左侧的参数为右侧参数赋予默认值!

例如:

 add(a, b = a)
   a + b

 add(10, 5)
 // => 15
 
 add(10)
 // => 20

注意: 因为参数默认是赋值,因此我们可以使用函数调用作为默认值:

 add(a, b = unit(a, px))
   a + b

命名参数

函数可以接受命名参数。这可以免去记忆参数顺序的麻烦,或者说是提供了代码的可读性。

例如:

subtract(a, b)
  a - b

subtract(b: 10, a: 25)

函数体

我们把 add() 函数做进一步的扩展。通过内置 unit() 函数把所有参数的数值单位都变成 px。因为它为每个参数重新赋值了,并且每个参数都提供了字符串标识数值单位类型,因此,可以无视单位换算的内部机制。

 add(a, b = a)
   a = unit(a, px)
   b = unit(b, px)
   a + b

 add(15%, 10deg)
 // => 25

多个返回值

Stylus 函数可以返回多个值,就像你给一个变量赋予多个值一样。

例如,下面就是一个有效的赋值:

   sizes = 15px 10px
 
   sizes[0]
   // => 15px 

类似的,我们可以在函数中返回多个值:

   sizes()
     15px 10px

   sizes()[0]
   // => 15px

当返回值是标识符时是个小小的例外。例如,下面的代码对于 Stylus 来说看上去好像一个属性赋值(但是没有赋值操作符):

 swap(a, b)
   b a

为避免歧义,我们可以使用括号,或是 return 关键字:

  swap(a, b)
    (b a)

  swap(a, b)
    return b a

条件

假设我们想要创建一个名为 stringish() 的函数,用来决定参数是否可以转换为字符串。我们检查 val 是否是字符串或缩进(类似字符)。由于未定义的标识符将其自身作为值,因此我们就可以像下面一样对其自身进行比较(使用 yesno 代替 truefalse):

 stringish(val)
   if val is a 'string' or val is a 'ident'
     yes
   else
     no

用法:

 stringish('yay') == yes
 // => true
   
 stringish(yay) == yes
 // => true
   
 stringish(0) == no
 // => true

注意: yesno 并不是布尔字面量(boolean literals)。他们在这里只是简单的未定义标识符。

另外一个例子:

compare(a, b)
  if a > b
    higher
  else if a < b
    lower
  else
    equal

用法:

compare(5, 2)
// => higher

compare(1, 5)
// => lower

compare(10, 10)
// => equal

别名

将函数名赋值给一个新的标识符就为其创建了一个别名。例如,我们前面定义的 add() 函数就可以起一个别名叫做 plus(),如下所示:

  plus = add
  
  plus(1, 2)
  // => 3

函数作为变量使用

与为函数起 “别名” 一样,我们可以将函数作为参数传递。如下, invoke() 函数能够接收一个函数作为参数,因此我们可以将 add()sub() 函数作为参数传递给 invoke()

add(a, b)
  a + b

sub(a, b)
  a - b

invoke(a, b, fn)
  fn(a, b)

body
  padding invoke(5, 10, add)
  padding invoke(5, 10, sub)

生成:

body {
  padding: 15;
  padding: -5;
}

匿名函数

利用 @(){} 语法可以在需要的地方使用匿名函数。下面展示了如何利用匿名函数创建一个自定义的 sort() 函数:

sort(list, fn = null)
  // default sort function
  if fn == null
    fn = @(a, b) {
      a > b
    }

  // bubble sort
  for $i in 1..length(list) - 1
    for $j in 0..$i - 1
      if fn(list[$j], list[$i])
        $temp = list[$i]
        list[$i] = list[$j]
        list[$j] = $temp
  return list

  sort('e' 'c' 'f' 'a' 'b' 'd')
  // => 'a' 'b' 'c' 'd' 'e' 'f'

  sort(5 3 6 1 2 4, @(a, b){
    a < b
  })
  // => 6 5 4 3 2 1

参数

arguments 是所有函数体都能够访问的局部变量,包含了传递过来的所有参数。

例如:

 sum()
   n = 0
   for num in arguments
     n = n + num

 sum(1,2,3,4,5)
 // => 15

Hash 实例

下面我们定义了 get(hash, key) 函数,返回 key 的值或 null。我们遍历 hash 中的每个键值对(pair),如果键(key)相匹配则返回对应的值。

  get(hash, key)
    return pair[1] if pair[0] == key for pair in hash

如下所示,语言内置的函数功能和 Stylus 表达式相结合,能够提供强大的灵活性:

  hash = (one 1) (two 2) (three 3)
  
  get(hash, two)
  // => 2

  get(hash, three)
  // => 3

  get(hash, something)
  // => null
Stylus on GitHub