從一行代碼裏學點JavaScript

轉載自野狗公衆號

這段代碼,它來自於谷歌“名猿”Addy Osmani在幾天前貼出的一段代碼,它的作用是用來調試你的CSS層。全部代碼只有三行,但是你絕對可以把它放在一行裏面完成:

[].forEach.call($$("*"),function(a){

  a.style.outline="1px solid #"+(~~(Math.random()*(1<<24))).toString(16)

})

在你Chrome瀏覽器的控制檯中輸入這段代碼,會發現不同HTML層都被使用不同的顏色添加了一個高亮的邊框。簡單來說,這段代碼只是首先獲取了所有的頁面元素,然後使用一個不同的顏色爲它們添加了一個1px的邊框。

選擇頁面中所有的元素

  上面的代碼使用了一個Chrome瀏覽器中特有的函數$$,例如在Chrome瀏覽器控制檯中輸入$$('a'),就能得到一個當前頁面中所有錨元素的列表。
  $$函數是許多現代瀏覽器命令行API中的一個部分,它等價於document.querySelectorAll。也可以將CSS選擇器作爲這個函數的參數,就能夠獲得當前頁面中所有匹配這個CSS選擇器的元素列表。
  在瀏覽器控制檯以外的地方,可以使用document.querySelectorAll('*') 來代替$$('*')。此外,還有一種更簡單的方法,使用document.all,雖然這並不是一種很規範的使用方法,但是它幾乎在每一個瀏覽器中都能運行成功。
  

迭代所有的元素

  通過選擇器獲得的列表是一個NodeLists對象,它和JavaScript中的數組有點像,可以使用方括號來獲取其中的節點,也可以檢查它其中包含多少個元素,但是它並沒有實現數組包含的所有方法,因此我們並不能使用$$('*').forEach()來進行迭代。
  在JavaScript中,有好幾個類似於數組但是並不是數組的對象,除了前面的NodeLists,還有函數的參數集合arguments,在這裏我們可以使用callapply函數將函數的方法運用到這些對象上。例如下面的例子:

function say(name) {
 console.log( this + ' ' + name );
}
say.call( 'hola', 'Mike' ); // 打印 'hola Mike'

  這裏把say函數作用到了字符串對象”hola”上,執行的時候this被替換爲“hola”,name被替換爲“mike”。

爲元素添加顏色

爲了讓元素都有一個漂亮的邊框,我們在上面的代碼中使用了CSS屬性outline。outline屬性位於CSS盒模型之外,因此它並不影響元素的屬性或者元素在佈局中的位置,這對於我們來說非常有用。這個屬性和修改border屬性非常類似,因此下面的代碼應該不會很難理解:

a.style.outline=”1px solid #” + color

  真正有趣的地方在於定義顏色部分:

~~(Math.random()*(1<<24))).toString(16)

在JavaScript中,比特操作符並不是經常被使用,因此這裏可能會讓很多程序員感到很疑惑。

我們想達到的目的是活的一個十六進制格式的顏色例如白色對應的是FFFFFF,藍色對應的是0000FF,或者隨便一個顏色37f9ac。雖然我們人類喜歡十進制,但是我們的代碼常常會需要十六進制的東西。

我們首先要學會如何使用toString函數將一個十進制的數組轉換爲一個十六進制整數。這個函數可以接受一個參數,如果參數缺省,默認爲十進制,但是你完全可以使用別的數組:

(30).toString(); // "30"
(30).toString(10); // "30"
(30).toString(16); // "1e" 十六進制
(30).toString(2); // "11110" 二進制
(30).toString(36); // "u" 36是允許的最大參數值

除此之外,你可以使用parseInt函數將十六進制數字轉換爲十進制。

parseInt("30"); // "30"
parseInt("30", 10); // "30"
parseInt("1e", 16); // "30"
parseInt("11110", 2); // "30"
parseInt("u", 36); // "30"

因此,我們現在只需要一個位於0和ffffff之間的十六進制數,由於:

parseInt("ffffff", 16) == 16777215
而這裏的16777215實際上是2^24-1。
如果你對二進制數學熟悉的話,你可能會知道1<<24 == 16777216。
再進一步,你每在1後面添加一個0,你就相當於多做了一次2的乘方:

1 // 1 == 2^0
100 // 4 == 2^2
10000 // 16 == 2^4
1000000000000000000000000 // 16777216 == 2^24

因此,在這裏我們可以知道Math.random()*(1<<24)表示一個位於0和16777216之間的數。

但是這裏並沒有結束,因爲Math.random返回的是一個浮點數,但是我們只想要整數部分。我們的代碼中使用波浪號操作符來完成這件事。波浪操作符在JavaScript中被用來對一個變量進行取反。

但是我們在這裏並不關心取反,我們指向獲取整數部分。因此我們還可以知道兩次取反可以去掉一個浮點數的小數部分,因此~~的作用相當於parseInt:

var a = 12.34, // ~~a = 12
    b = -1231.8754, // ~~b = -1231
    c = 3213.000001; // ~~c = 3213


~~a == parseInt(a, 10); // true
~~b == parseInt(b, 10); // true
~~c == parseInt(c, 10); // true

當然,我們還有一種更加簡潔的方法,使用OR操作符:

~~a == 0|a == parseInt(a, 10)
~~b == 0|b == parseInt(b, 10)
~~c == 0|c == parseInt(c, 10)

最終,我們獲得了一個位於0和16777216之間的隨機整數,也就是我們想要的隨機顏色。此時我們只需要使用toString(16)將它轉化爲十六進制數即可。

總結

現在,你已經完全理解了前面的這一行代碼中的各個部分。作爲一個程序員,我們應該在完成工作之後多問自己幾遍爲什麼,還有沒有更好更簡潔的方法。當然,最應該做的事情當然是多閱讀程序代碼,也許你就能從某一行代碼中學到很多新東西。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章