iT邦幫忙

1

奇妙的一行JS程式碼之完整解析

  • 分享至 

  • xImage
  •  

這段程式是我在網路上無意間看到的,如果你把這段程式碼貼到開發人員工具的 console 會看到像下圖一樣出現一堆框線XDD
[].forEach.call($$("*"),function(a){a.style.outline="1px solid #"+(~~(Math.random()*(1<<24))).toString(16)})

那我們就來看懂這段程式到底在做啥,不過簡單的來說就是抓取頁面所有元素並且給予它們隨機顏色的邊框。

我們先看到 [].forEach.call($$("*"), function(a){...}) 的部分:

  1. $$('') 意義等同於 document.querySelectorAll(''),可以參考以下連結:
    https://developers.google.com/web/tools/chrome-devtools/console/utilities#queryselectorall

  2. [] 等同於 Array.prototype。為陣列 Array 的原型,它定義了陣列的一系列方法,從附圖可以知道 Array.prototype 包括了許多我們在操作陣列會用到的方法。

順便一提,這邊要有原型和繼承的概念才比較了解在做啥

  1. 了解以上兩點後,原本的程式就可以看做:
Array.prototype.forEach.call(document.querySelectorAll('*'), function(a){...})

那麼為何不使用 document.querySelectorAll('*').forEach(function() {}); 去選擇所有元素呢,這樣不是比較淺顯易懂嗎?那是因為 document.querySelectorAll() 會回傳一組 NodeList,而 NodeList 在比較舊的瀏覽器可能不支援搭配 forEach 這樣的寫法(目前比較新的瀏覽器已經可以這樣寫了),因此用陣列搭配 forEach 和 call 來選取所有頁面元素。

補充:

關於 NodeList: 它包括了DOM元素節點,文字和屬性,以<div id="title">Hello world</div> 為例,DOM元素節點就是<div>,文字為Hello world,屬性為id="title"
mozilla上NodeList的介紹:
https://developer.mozilla.org/en-US/docs/Web/API/NodeList

forEach() + call() 的使用參考:
https://stackoverflow.com/questions/16053357/what-does-foreach-call-do-in-javascript

接著我們來看 function 裡面的這段內容:
function(a){a.style.outline="1px solid #"+(~~(Math.random()*(1<<24))).toString(16)}

  1. 在此就是將剛剛透過 document.querySelectorAll('*') 取到的NodeList一個個傳入這個函式,並為它們加上寬度 1px 的框線,#"+(~~(Math.random()*(1<<24))).toString(16) 產生的就是16進位的色碼。

  2. (1<<24)的部分,就是將1變成1000...總共24位數,而且為二進位制的型態,轉為十進位此數字將為16,777,216
    可以參考:
    https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#%E4%BD%8D%E5%85%83%E4%BD%8D%E7%A7%BB%E9%81%8B%E7%AE%97%E5%AD%90

備註: 這邊要有進位制概念才看得懂在做啥

  1. ~~ 這個符號,效用幾乎相等於 Math.floor() (在正整數的情況下兩者結果都會相等,負數則不會)~ 它就是位元運算子的其中一個,而 ~~ 就是做兩次 NOT 運算
~(4.5) // -5
~(-4.5) // 3
~~(4.5) // 4
~~(-4.5) // -4

參考資料:
https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#(%E4%BD%8D%E5%85%83_NOT)

  1. 最後是 toString(),這相當好理解就是將前面的一串東西轉為字串,()裡面的參數則是代表數字的進位制。

因此 (~~(Math.random()*(1<<24))).toString(16) 這段我們可以理解就是取 0~16,777,216 的亂數並去掉小數點,再轉為16進位的數字再變成字串,最後得到16進位的隨機色碼,例如 #FFFFFF 白色,也因此我們才會在輸入整段程式碼的網頁看到一堆五顏六色的邊框XDD。

最後的小心得就是短短的一段程式碼裡面竟然包含了不少觀念,寫出這段程式碼的人實力真的堅強,自己也查到是 Google 的工程師 Addy Osmani 寫的,也附上這段程式來源的 Github Gist 給大家看看:
https://gist.github.com/addyosmani/fd3999ea7fce242756b1
有機會也可以逛逛這位大神的 Github,感受一下所謂的大神是什麼樣子哈哈哈。


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
dragonH
iT邦超人 5 級 ‧ 2019-10-25 21:26:02
[...$$('*')].forEach(a => a.style.outline=`1px solid #${(~~(Math.random()*(1<<24))).toString(16)}`)

我先去 google 面試了XD

/images/emoticon/emoticon48.gif/images/emoticon/emoticon48.gif/images/emoticon/emoticon48.gif

除了 1<<24 其他應該都還算是常用的

harry xie iT邦研究生 1 級 ‧ 2019-10-25 21:49:23 檢舉

可...可惡,是我太菜啦~才覺得寫出這段程式碼很厲害
/images/emoticon/emoticon06.gif
總之學到不少東西就是

dragonH iT邦超人 5 級 ‧ 2019-10-25 22:00:27 檢舉

沒有啦 就像你說的

code 很簡單

但是包含了很多觀念XD

感謝分享 /images/emoticon/emoticon32.gif

我要留言

立即登入留言