跳至內容

運算子

運算子優先順序

以下是運算子優先順序表,由高到低

.
[]
! ~ + -
is defined
** * / %
+ -
... ..
<= >= < >
in
== is != is not isnt
is a
&& and || or
?:
= := ?= += -= *= /= %=
not
if unless
.
[]
! ~ + -
is defined
** * / %
+ -
... ..
<= >= < >
in
== is != is not isnt
is a
&& and || or
?:
= := ?= += -= *= /= %=
not
if unless

一元運算子

以下是一元運算子,!not-+~

!0
// => true

!!0
// => false

!1
// => false

!!5px
// => true

-5px
// => -5px

--5px
// => 5px

not true
// => false

not not true
// => true
!0
// => true

!!0
// => false

!1
// => false

!!5px
// => true

-5px
// => -5px

--5px
// => 5px

not true
// => false

not not true
// => true

邏輯 not 運算子的優先順序較低,因此以下範例可以用取代

a = 0
b = 1

!a and !b
// => false
// parsed as: (!a) and (!b)
a = 0
b = 1

!a and !b
// => false
// parsed as: (!a) and (!b)

使用

not a or b
// => false
// parsed as: not (a or b)
not a or b
// => false
// parsed as: not (a or b)

二元運算子

下標 []

下標運算子讓我們能透過索引(從 0 開始)取得表達式中的值。負索引值從表達式中的最後一個元素開始。

list = 1 2 3
list[0]
// => 1

list[-1]
// => 3
list = 1 2 3
list[0]
// => 1

list[-1]
// => 3

括號中的表達式可以作為元組(例如 (15px 5px)(1 2 3))。

以下是一個使用元組進行錯誤處理(並展示此結構的多功能性)的範例

add(a, b)
  if a is a 'unit' and b is a 'unit'
    a + b
  else
    (error 'a and b must be units!')

body
  padding add(1,'5')
  // => padding: error "a and b must be units";
  
  padding add(1,'5')[0]
  // => padding: error;
  
  padding add(1,'5')[0] == error
  // => padding: true;

  padding add(1,'5')[1]
  // => padding: "a and b must be units";
add(a, b)
  if a is a 'unit' and b is a 'unit'
    a + b
  else
    (error 'a and b must be units!')

body
  padding add(1,'5')
  // => padding: error "a and b must be units";
  
  padding add(1,'5')[0]
  // => padding: error;
  
  padding add(1,'5')[0] == error
  // => padding: true;

  padding add(1,'5')[1]
  // => padding: "a and b must be units";

以下是一個更複雜的範例。現在我們呼叫內建的 error() 函數,並傳回錯誤訊息,只要識別碼(第一個值)等於 error

if (val = add(1,'5'))[0] == error
  error(val[1])
if (val = add(1,'5'))[0] == error
  error(val[1])

範圍 .. ...

提供包含(..)和排除(...)範圍運算子,擴充至表達式

1..5
// => 1 2 3 4 5

1...5
// => 1 2 3 4

5..1
// => 5 4 3 2 1
1..5
// => 1 2 3 4 5

1...5
// => 1 2 3 4

5..1
// => 5 4 3 2 1

加法:+ -

乘法和加法二元運算子如預期般運作。類型轉換套用於單位類型類別中,或預設為文字值。例如 5s - 2px 的結果為 3s

15px - 5px
// => 10px

5 - 2
// => 3

5in - 50mm
// => 3.031in

5s - 1000ms
// => 4s

20mm + 4in
// => 121.6mm

"foo " + "bar"
// => "foo bar"

"num " + 15
// => "num 15"
15px - 5px
// => 10px

5 - 2
// => 3

5in - 50mm
// => 3.031in

5s - 1000ms
// => 4s

20mm + 4in
// => 121.6mm

"foo " + "bar"
// => "foo bar"

"num " + 15
// => "num 15"

乘法:/ * %

2000ms + (1s * 2)
// => 4000ms

5s / 2
// => 2.5s

4 % 2
// => 0
2000ms + (1s * 2)
// => 4000ms

5s / 2
// => 2.5s

4 % 2
// => 0

在屬性值中使用 / 時,必須用括號括起來。否則 / 會被視為文字(以支援 CSS line-height

font: 14px/1.5;
font: 14px/1.5;

但以下會評估為 14px ÷ 1.5

font: (14px/1.5);
font: (14px/1.5);

/ 運算子需要這樣做。

簡寫運算子:+= -= *= /= %=

簡寫運算子與其他常見語言類似。對於清單變數,第一個值會用來執行運算子,並覆寫清單以將其轉換為單值變數。對於字串,節點值只有 += 可作為附加函數。對於數字類型值,所有運算子都像一般數學運算一樣運作。顏色值也類似。

n = 12
n += 8
// => n = 20

int-list = 12 23 0 32
int-list %= 2
// => 12 % 2 = 0 (mod operator)
// => int-list = 0

mixed-list = node 23 'str'
mixed-list %= 2
// => error

mixed-list = node 23 'str' #2e7
mixed-list += 2
// => mixed-list = node2

s = 'str'
s += 2
// => s = 'str2'

c = #0e0
c -= #0e0
// => c = #000    
n = 12
n += 8
// => n = 20

int-list = 12 23 0 32
int-list %= 2
// => 12 % 2 = 0 (mod operator)
// => int-list = 0

mixed-list = node 23 'str'
mixed-list %= 2
// => error

mixed-list = node 23 'str' #2e7
mixed-list += 2
// => mixed-list = node2

s = 'str'
s += 2
// => s = 'str2'

c = #0e0
c -= #0e0
// => c = #000    

指數:**

指數運算子

2 ** 8
// => 256
2 ** 8
// => 256

相等性與關係:== != >= <= > <

相等性運算子可用於等同單位、顏色、字串,甚至識別碼。這是一個強大的概念,因為即使是任意識別碼(例如 wahoo)也可以用作原子。函數可以傳回 yesno,而不是 truefalse(儘管不建議這樣做)。

5 == 5
// => true

10 > 5
// => true

#fff == #fff
// => true

true == false
// => false

wahoo == yay
// => false

wahoo == wahoo
// => true

"test" == "test"
// => true

true is true
// => true

'hey' is not 'bye'
// => true

'hey' isnt 'bye'
// => true

(foo bar) == (foo bar)
// => true

(1 2 3) == (1 2 3)
// => true

(1 2 3) == (1 1 3)
// => false
5 == 5
// => true

10 > 5
// => true

#fff == #fff
// => true

true == false
// => false

wahoo == yay
// => false

wahoo == wahoo
// => true

"test" == "test"
// => true

true is true
// => true

'hey' is not 'bye'
// => true

'hey' isnt 'bye'
// => true

(foo bar) == (foo bar)
// => true

(1 2 3) == (1 2 3)
// => true

(1 2 3) == (1 1 3)
// => false

只有精確值相符。例如,0 == falsenull == false 都是 false

別名

==    is
!=    is not
!=    isnt
==    is
!=    is not
!=    isnt

真值

Stylus 中幾乎所有內容都解析為 true,包括帶有後綴的單位。即使是 0%0px 等也會解析為 true(因為在 Stylus 中,混入或函數通常會接受單位作為有效值)。

但是,就算術而言,0 本身是 false

長度大於 1 的表達式(或「清單」)被視為真值。

true 範例

      0% 
      0px
      1px 
      -1
      -1px
      hey
      'hey'
      (0 0 0)
      ('' '')
      0% 
      0px
      1px 
      -1
      -1px
      hey
      'hey'
      (0 0 0)
      ('' '')

false 範例

0 
null
false
''
0 
null
false
''

邏輯運算子:&& || and or

邏輯運算子 &&|| 是別名 and / or,它們套用相同的優先順序。

5 && 3
// => 3

0 || 5
// => 5

0 && 5
// => 0

#fff is a 'rgba' and 15 is a 'unit'
// => true
5 && 3
// => 3

0 || 5
// => 5

0 && 5
// => 0

#fff is a 'rgba' and 15 is a 'unit'
// => true

存在運算子:in

檢查 左邊 運算元在 右邊 表達式中是否存在。

簡單範例

nums = 1 2 3
1 in nums
// => true

5 in nums
// => false
nums = 1 2 3
1 in nums
// => true

5 in nums
// => false

一些未定義的識別碼

words = foo bar baz
bar in words
// => true

HEY in words
// => false
words = foo bar baz
bar in words
// => true

HEY in words
// => false

也可以用於元組

vals = (error 'one') (error 'two')
error in vals
// => false

(error 'one') in vals
// => true

(error 'two') in vals
// => true

(error 'something') in vals
// => false
vals = (error 'one') (error 'two')
error in vals
// => false

(error 'one') in vals
// => true

(error 'two') in vals
// => true

(error 'something') in vals
// => false

混入中的範例用法

pad(types = padding, n = 5px)
  if padding in types
    padding n
  if margin in types
    margin n

body
  pad()

body
  pad(margin)

body
  pad(padding margin, 10px)
pad(types = padding, n = 5px)
  if padding in types
    padding n
  if margin in types
    margin n

body
  pad()

body
  pad(margin)

body
  pad(padding margin, 10px)

產生

body {
  padding: 5px;
}
body {
  margin: 5px;
}
body {
  padding: 10px;
  margin: 10px;
}
body {
  padding: 5px;
}
body {
  margin: 5px;
}
body {
  padding: 10px;
  margin: 10px;
}

條件賦值:?= :=

條件賦值運算子 ?=(別名為 :=)讓我們可以在不覆蓋舊值(如果存在)的情況下定義變數。此運算子會擴充為三元運算中的 is defined 二元運算。

例如,下列範例是等效的

color := white
color ?= white
color = color is defined ? color : white
color := white
color ?= white
color = color is defined ? color : white

使用一般的 = 時,我們只是重新指派

color = white
color = black

color
// => black
color = white
color = black

color
// => black

但使用 ?= 時,我們的第二次嘗試會失敗(因為變數已經定義)

color = white
color ?= black

color
// => white
color = white
color ?= black

color
// => white

實例檢查:是一個

Stylus 提供一個名為 is a 的二元運算子,用於類型檢查。

15 is a 'unit'
// => true

#fff is a 'rgba'
// => true

15 is a 'rgba'
// => false
15 is a 'unit'
// => true

#fff is a 'rgba'
// => true

15 is a 'rgba'
// => false

或者,我們可以使用 type() BIF

type(#fff) == 'rgba'
// => true                                                                            
type(#fff) == 'rgba'
// => true                                                                            

注意: color 是唯一的特殊情況,當左手運算元是 RGBAHSLA 節點時,會評估為 true

變數定義:已定義

這個偽二元運算子不接受右手運算元,並且不會評估左手。這讓我們可以檢查變數是否有指派值。

foo is defined
// => false

foo = 15px
foo is defined
// => true

#fff is defined
// => 'invalid "is defined" check on non-variable #fff'
foo is defined
// => false

foo = 15px
foo is defined
// => true

#fff is defined
// => 'invalid "is defined" check on non-variable #fff'

或者,可以使用 lookup(name) 內建函數來執行此操作,或執行動態查詢

name = 'blue'
lookup('light-' + name)
// => null

light-blue = #80e2e9
lookup('light-' + name)
// => #80e2e9
name = 'blue'
lookup('light-' + name)
// => null

light-blue = #80e2e9
lookup('light-' + name)
// => #80e2e9

這個運算子是必要的,因為未定義的識別碼仍然是真值。例如

body
  if ohnoes
    padding 5px
body
  if ohnoes
    padding 5px

未定義時產生下列 CSS

body {
  padding: 5px;
}
body {
  padding: 5px;
}

然而這會是安全的

body
  if ohnoes is defined
    padding 5px
body
  if ohnoes is defined
    padding 5px

三元

三元運算子在大部分語言中都像我們預期的那樣運作。它是唯一具有三個運算元的運算子(條件表達式、表達式和表達式)。

num = 15
num ? unit(num, 'px') : 20px
// => 15px
num = 15
num ? unit(num, 'px') : 20px
// => 15px

強制轉型

作為 unit() 內建函數的簡潔替代方案,語法 (expr) unit 可用於強制後綴。

body
  n = 5
  foo: (n)em
  foo: (n)%
  foo: (n + 5)%
  foo: (n * 5)px
  foo: unit(n + 5, '%')
  foo: unit(5 + 180 / 2, deg)
body
  n = 5
  foo: (n)em
  foo: (n)%
  foo: (n + 5)%
  foo: (n * 5)px
  foo: unit(n + 5, '%')
  foo: unit(5 + 180 / 2, deg)

顏色運算

對顏色的操作提供簡潔、有表現力的方式來改變組成。例如,我們可以對每個 RGB

#0e0 + #0e0
// => #0f0
#0e0 + #0e0
// => #0f0

另一個範例是透過加或減百分比來調整明度值。要使顏色變亮,請加;要使顏色變暗,請減。

#888 + 50%
// => #c3c3c3

#888 - 50%
// => #444
#888 + 50%
// => #c3c3c3

#888 - 50%
// => #444

也可以透過加或減度數來調整色相。例如,將 50deg 加到這個紅色值會產生一個黃色

#f00 + 50deg
// => #ffd500
#f00 + 50deg
// => #ffd500

值會適當地固定。例如,我們可以將色相「旋轉」180度,如果目前的值是 320deg,它將解析為 140deg

我們也可以一次調整多個值(包括 alpha),方法是使用 rgb()rgba()hsl()hsla()

#f00 - rgba(100,0,0,0.5)
// => rgba(155,0,0,0.5)
#f00 - rgba(100,0,0,0.5)
// => rgba(155,0,0,0.5)

Sprintf

字串 sprintf 類型的運算子 % 可用於產生一個字面值,在內部透過 s() 內建函式傳遞參數

'X::Microsoft::Crap(%s)' % #fc0
// => X::Microsoft::Crap(#fc0)
'X::Microsoft::Crap(%s)' % #fc0
// => X::Microsoft::Crap(#fc0)

多個值應加上括號

'-webkit-gradient(%s, %s, %s)' % (linear (0 0) (0 100%))
// => -webkit-gradient(linear, 0 0, 0 100%)
'-webkit-gradient(%s, %s, %s)' % (linear (0 0) (0 100%))
// => -webkit-gradient(linear, 0 0, 0 100%)