摘要:下一步,我聲明了變量和,然后把他們放在函數(shù)的頂部。注意,我將上述的剩余部分重命名為。會(huì)返回一個(gè)從開(kāi)始的整數(shù),并且每次執(zhí)行完之后返回值都會(huì)遞增。行之后超過(guò)了,使得結(jié)果發(fā)生了變化。這和我們的預(yù)期一致。這一時(shí)刻的數(shù)量已經(jīng)增長(zhǎng)了一定的數(shù)量。
原文地址:Reverse Engineering One Line of JavaScript
原文作者:Alex Kras
譯者:李波
校對(duì)者:冬青、小蘿卜
幾個(gè)月前,我看到一個(gè)郵件問(wèn):有沒(méi)有人可以解析這一行 JavaScript 代碼
這一行代碼會(huì)被渲染成下圖的效果。你可以在這里用瀏覽器打開(kāi)來(lái)觀(guān)看。這是 Mathieu ‘p01’ Henri 寫(xiě)的,你還可以在作者的網(wǎng)站www.p01.org里看到更多很酷的例子。
好的!我決定接受挑戰(zhàn)
第一步:讓代碼變得可讀第一件事,讓 HTML 文件里只有 HTML 代碼,然后把 JavaScript 代碼放到 code.js 文件里。我還用 id="p" 來(lái)包裝 pre 標(biāo)簽。
index.html
我注意到變量 k 只是一個(gè)常量,所以把它移出來(lái),然后重命名為 delay。
code.js
var delay = 64; var draw = "for(n+=7,i=delay,P="p. ";i-=1/delay;P+=P[i%2?(i%2*j-j+n/delay^j)&1:2])j=delay/i;p.innerHTML=P"; var n = setInterval(draw, delay);接下來(lái),因?yàn)?setInterval 可以接收一個(gè)函數(shù)或者字符串來(lái)執(zhí)行,字符串 var draw 會(huì)被 setInterval 用 eval 來(lái)解析并執(zhí)行。所以我把它移到一個(gè)新建的函數(shù)體內(nèi)。 然后保留舊的那行代碼,以供參考。
我注意到的另一個(gè)點(diǎn),變量 p 指向了存在于 HTML 的 DOM 結(jié)構(gòu)里 id 為 p 的標(biāo)簽,就是那個(gè)之前我包裝過(guò)的 pre 標(biāo)簽。事實(shí)上,元素標(biāo)簽可以通過(guò)他們的 id 用 JavaScript 來(lái)獲取,只要 id 僅由字母數(shù)字組成。這里,我通過(guò) document.getElementById("p") 來(lái)讓它更加直觀(guān)。
var delay = 64; var p = document.getElementById("p"); // < -------------- // var draw = "for(n+=7,i=delay,P="p. ";i-=1/delay;P+=P[i%2?(i%2*j-j+n/delay^j)&1:2])j=delay/i;p.innerHTML=P"; var draw = function() { for (n += 7, i = delay, P = "p. "; i -= 1 / delay; P += P[i % 2 ? (i % 2 * j - j + n / delay ^ j) & 1 : 2]) { j = delay / i; p.innerHTML = P; } }; var n = setInterval(draw, delay);下一步,我聲明了變量 i、p 和 j,然后把他們放在函數(shù)的頂部。
var delay = 64; var p = document.getElementById("p"); // var draw = "for(n+=7,i=delay,P="p. ";i-=1/delay;P+=P[i%2?(i%2*j-j+n/delay^j)&1:2])j=delay/i;p.innerHTML=P"; var draw = function() { var i = delay; // < --------------- var P ="p. "; var j; for (n += 7; i > 0 ;P += P[i % 2 ? (i % 2 * j - j + n / delay ^ j) & 1 : 2]) { j = delay / i; p.innerHTML = P; i -= 1 / delay; } }; var n = setInterval(draw, delay);我把 for 循環(huán)分解成 while 循環(huán)。只保留了 for 的CHECK_EVERY_LOOP部分(for的三個(gè)部分分別是RUNS_ONCE_ON_INIT; CHECK_EVERY_LOOP; DO_EVERY_LOOP),然后分別把其他的代碼移到循環(huán)的內(nèi)外部。
var delay = 64; var p = document.getElementById("p"); // var draw = "for(n+=7,i=delay,P="p. ";i-=1/delay;P+=P[i%2?(i%2*j-j+n/delay^j)&1:2])j=delay/i;p.innerHTML=P"; var draw = function() { var i = delay; var P ="p. "; var j; n += 7; while (i > 0) { // <---------------------- //Update HTML p.innerHTML = P; j = delay / i; i -= 1 / delay; P += P[i % 2 ? (i % 2 * j - j + n / delay ^ j) & 1 : 2]; } }; var n = setInterval(draw, delay);接著我將會(huì)展開(kāi) P += P[i % 2 ? (i % 2 * j - j + n / delay ^ j) & 1 : 2] 中的三元操作(判斷條件 ? true時(shí)運(yùn)行 :false時(shí)運(yùn)行)
i % 2 是用來(lái)檢測(cè) i 是奇數(shù)還是偶數(shù),如果 i 是偶數(shù),則返回 2。如果是奇數(shù),則返回 (i % 2 * j - j + n / delay ^ j) & 1 的計(jì)算結(jié)果(更多的是這種情況)。
最終,這個(gè)返回值被當(dāng)作索引,被用于獲取字符串P的某個(gè)字符,因此它可以寫(xiě)成 P += P[index]。
var delay = 64; var p = document.getElementById("p"); // var draw = "for(n+=7,i=delay,P="p. ";i-=1/delay;P+=P[i%2?(i%2*j-j+n/delay^j)&1:2])j=delay/i;p.innerHTML=P"; var draw = function() { var i = delay; var P ="p. "; var j; n += 7; while (i > 0) { //Update HTML p.innerHTML = P; j = delay / i; i -= 1 / delay; let index; let iIsOdd = (i % 2 != 0); // <--------------- if (iIsOdd) { // <--------------- index = (i % 2 * j - j + n / delay ^ j) & 1; } else { index = 2; } P += P[index]; } }; var n = setInterval(draw, delay);下一步,我會(huì)把 index = (i % 2 * j - j + n / delay ^ j) & 1 里的 & 1 分解到另外的 if 表達(dá)式里。
這是一種聰明的方法來(lái)檢測(cè)括號(hào)內(nèi)的值是奇數(shù)還是偶數(shù),如果是偶數(shù)則返回 0,反之返回 1.& 是與的位運(yùn)算符。與的邏輯如下:
1 & 1 = 1
0 & 1 = 0
因此 something & 1 則可以看成把“something”轉(zhuǎn)化成二進(jìn)制,接著在 1 的前面填充對(duì)應(yīng)數(shù)量的 0,從而保持和 something 的長(zhǎng)度一致,然后僅僅返回與運(yùn)算的最后一位。例如,5的二進(jìn)制是 101。如果我們和 1 進(jìn)行與運(yùn)算,將會(huì)得到如下結(jié)果:
101 AND 001 001或者說(shuō),5是一個(gè)奇數(shù),5 & 1 的結(jié)果是 1。用 JavaScript 的控制臺(tái)很容易可以證明下面這個(gè)邏輯。
0 & 1 // 0 - even return 0 1 & 1 // 1 - odd return 1 2 & 1 // 0 - even return 0 3 & 1 // 1 - odd return 1 4 & 1 // 0 - even return 0 5 & 1 // 1 - odd return 1注意,我將上述 index 的剩余部分重命名為 magic。因此這些代碼加上展開(kāi) & 1 后的代碼看起來(lái)是下面這樣的。
var delay = 64; var p = document.getElementById("p"); // var draw = "for(n+=7,i=delay,P="p. ";i-=1/delay;P+=P[i%2?(i%2*j-j+n/delay^j)&1:2])j=delay/i;p.innerHTML=P"; var draw = function() { var i = delay; var P ="p. "; var j; n += 7; while (i > 0) { //Update HTML p.innerHTML = P; j = delay / i; i -= 1 / delay; let index; let iIsOdd = (i % 2 != 0); if (iIsOdd) { let magic = (i % 2 * j - j + n / delay ^ j); let magicIsOdd = (magic % 2 != 0); // &1 < -------------------------- if (magicIsOdd) { // &1 <-------------------------- index = 1; } else { index = 0; } } else { index = 2; } P += P[index]; } }; var n = setInterval(draw, delay);接下來(lái),我將會(huì)分解 P += P[index] 到一個(gè) switch 表達(dá)式里。現(xiàn)在我們可以很清晰的知道 index的值只可能為 0、1 和 2 中的一個(gè)。也可以知道 P 的初始化總是 var P ="p. ", index 為 0 時(shí)指向 p,為 1 時(shí)指向 .,為 2 時(shí)指向 —— 新的一行字符串。
var delay = 64; var p = document.getElementById("p"); // var draw = "for(n+=7,i=delay,P="p. ";i-=1/delay;P+=P[i%2?(i%2*j-j+n/delay^j)&1:2])j=delay/i;p.innerHTML=P"; var draw = function() { var i = delay; var P ="p. "; var j; n += 7; while (i > 0) { //Update HTML p.innerHTML = P; j = delay / i; i -= 1 / delay; let index; let iIsOdd = (i % 2 != 0); if (iIsOdd) { let magic = (i % 2 * j - j + n / delay ^ j); let magicIsOdd = (magic % 2 != 0); // &1 if (magicIsOdd) { // &1 index = 1; } else { index = 0; } } else { index = 2; } switch (index) { // P += P[index]; <----------------------- case 0: P += "p"; // aka P[0] break; case 1: P += "."; // aka P[1] break; case 2: P += " "; // aka P[2] } } }; var n = setInterval(draw, delay);我將簡(jiǎn)化 var n = setInterval(draw, delay)。setInterval 會(huì)返回一個(gè)從 1 開(kāi)始的整數(shù),并且每次執(zhí)行完 setInterval 之后返回值都會(huì)遞增。這個(gè)整數(shù)可以在 clearInterval 方法里面用到(用來(lái)取消定時(shí)器)。在我們的代碼里, setInterval 僅僅只會(huì)執(zhí)行一次,所以 n 可以簡(jiǎn)單的設(shè)置為 1.
我還把 delay 重命名為 DELAY 讓它看起來(lái)是一個(gè)常量。
最后但并非不重要的一點(diǎn),我用括號(hào)把 i % 2 * j - j + n / DELAY 包起來(lái),指明 ^ 異或運(yùn)算的執(zhí)行優(yōu)先度低于 %,*,-,+和/操作?;蛘哒f(shuō),所有的運(yùn)算操作都會(huì)比 ^ 先執(zhí)行。包裝后的代碼應(yīng)該是這樣的 ((i % 2 * j - j + n / DELAY) ^ j)。
// 之前我把 `p.innerHTML = P;` 放錯(cuò)地方了,更新后,把它移出了while循環(huán) const DELAY = 64; // approximately 15 frames per second 15 frames per second * 64 seconds = 960 frames var n = 1; var p = document.getElementById("p"); // var draw = "for(n+=7,i=delay,P="p. ";i-=1/delay;P+=P[i%2?(i%2*j-j+n/delay^j)&1:2])j=delay/i;p.innerHTML=P"; /** * Draws a picture * 128 chars by 32 chars = total 4096 chars */ var draw = function() { var i = DELAY; // 64 var P ="p. "; // First line, reference for chars to use var j; n += 7; while (i > 0) { j = DELAY / i; i -= 1 / DELAY; let index; let iIsOdd = (i % 2 != 0); if (iIsOdd) { let magic = ((i % 2 * j - j + n / DELAY) ^ j); // < ------------------ let magicIsOdd = (magic % 2 != 0); // &1 if (magicIsOdd) { // &1 index = 1; } else { index = 0; } } else { index = 2; } switch (index) { // P += P[index]; case 0: P += "p"; // aka P[0] break; case 1: P += "."; // aka P[1] break; case 2: P += " "; // aka P[2] } } //Update HTML p.innerHTML = P; }; setInterval(draw, 64);你可以在這里看到最后的結(jié)果。
第二步:理解代碼這部分將會(huì)介紹什么內(nèi)容呢?不要心急,讓我們一步一步來(lái)解析。
i 通過(guò) var i = DELAY,被初始化為 64,然后每次循環(huán)遞減 1/64,等于0.015625(i -= 1 / DELAY)。循環(huán)持續(xù)到 i 小于 0 時(shí)(while (i > 0) {)。每次執(zhí)行循環(huán),i 將會(huì)減少 1/64,所以每執(zhí)行 64 次循環(huán),i 就會(huì)減 1 (64 / 64 = 1),總得來(lái)說(shuō), i 需要執(zhí)行 64 x 64 = 4096 次,之后小于 0.
之前的圖片中,一共有 32 行,每行包含了 128 個(gè)字符。恰巧的是 64 x 64 = 32 x 128 = 4096。我們觸發(fā) 32 次 i 為嚴(yán)謹(jǐn)?shù)呐紨?shù)的情況,i 是絕對(duì)的偶數(shù)時(shí),i 才為偶數(shù)(非奇數(shù) let iIsOdd = (i % 2 != 0); 譯者提示:偶數(shù)是整數(shù),所以2.2是奇數(shù)),例如 i 為 64,62,60等。在這 32 次里,index 通過(guò) index = 2 賦值為 2,意味著字符串將添加 P += " "; // aka P[2] 從而換行,開(kāi)始一行新的字符串。剩余的 127 個(gè)字符則都是 p 和 .。
那么我們根據(jù)什么來(lái)判斷何時(shí)用 p 或者 . ?
當(dāng)然,之前我們就已經(jīng)知道了,當(dāng) let magic = ((i % 2 * j - j + n / DELAY) ^ j) 中的 magic 是奇數(shù)的時(shí)候用 . ,如果是偶數(shù)則用 p。
var P ="p. "; ... if (magicIsOdd) { // &1 index = 1; // second char in P - . } else { index = 0; // first char in P - p }但我們很難知道 magic 是奇數(shù)還是偶數(shù),這是一個(gè)很有分量的問(wèn)題。在此之前,讓我們證實(shí)一些事情。
如果我們把 + n/DELAY 從 let magic = ((i % 2 * j - j + n / DELAY) ^ j) 當(dāng)中移除掉,我們最終將會(huì)看到一個(gè)靜態(tài)的布局,如下圖
現(xiàn)在,讓我們來(lái)看看移除了 + n/DELAY 的 magic。如何能得到上面漂亮的圖片。
(i % 2 * j - j) ^ j
注意到每次循環(huán)里,我們都會(huì)執(zhí)行:
j = DELAY / i; i -= 1 / DELAY;換句話(huà)說(shuō),我們可以將上述表達(dá)式中的 j 用 i 表示,變成 j = DELAY/ (i + 1/DELAY),但因?yàn)?1/DELAY 是一個(gè)非常小的數(shù)值,所以我們暫時(shí)去掉 + 1/DELAY 并簡(jiǎn)化成 j = DELAY/i = 64/i
// 譯者注
為何這里不是 j = DELAY/ (i - 1/DELAY)呢?
原因:
i -= 1 / DELAY 轉(zhuǎn)化成 i = i - 1 / DELAY
這里有 2 個(gè) i 可以代入消元,但是因?yàn)?j 的表達(dá)式在 i 前面,所以 j 取得 i 應(yīng)
該是自減前的 i,故 i = i + 1/ DELAY因此我們可以重寫(xiě) (i % 2 * j - j) ^ j 為 (i % 2 * 64/i - 64/i) ^ 64/i
讓我們用在線(xiàn)的圖形計(jì)算器來(lái)繪制那些函數(shù)
首先,我們來(lái)繪制下 i%2 的圖
從下面的圖形可以看出,y 的值區(qū)間在 0 到 2 之間。
如果我們繪制 64 / i 則會(huì)得到如下圖形
如果我們繪制 (i % 2 * 64/i - 64/i) 表達(dá)式,我們將得到一個(gè)混合了上面兩張圖的一個(gè)圖形,如下
最后,如果我們把2個(gè)函數(shù)同時(shí)繪制出來(lái),將會(huì)是如下的圖(紅線(xiàn)為 j 的關(guān)系圖)
我們能從圖形里知道些什么?讓我們回憶下我們要去解答的問(wèn)題:如何得到如下靜止圖像:
好的,我們知道如果 (i % 2 * j - j) ^ j 的值是一個(gè)偶數(shù),那么我們將添加 p,如果是一個(gè)奇數(shù)則添加 . 。
讓我們專(zhuān)注在圖形的前面 16 行,i 的值在 64 到 32 之間。
異或運(yùn)算在 JavaScript 里會(huì)把小數(shù)點(diǎn)右邊的值忽略掉,所以它看起來(lái)和執(zhí)行 Math.floor 的效果一樣。
其實(shí)當(dāng)2個(gè)對(duì)比位都是 1 或者 0 的時(shí)候, 異或操作會(huì)返回0。
這里我們的 j 初始值為 1,且慢慢的遞增趨向于 2,但始終小于 2,所以我們可以把它當(dāng)成 1 來(lái)處理(Math.floor(1.9999) === 1),為了得到結(jié)果為 0 (意味著是偶數(shù)),我們還需要異或表達(dá)式的左邊也是 1,使得返回一個(gè) p 給我們。
換句話(huà)說(shuō),每條藏青色的傾斜線(xiàn)都相當(dāng)于我們圖像中的一行,因?yàn)榍懊?6行的 j 值總是介于 1 和 2 之間,而唯一能得到奇數(shù)值的方法是讓 (i % 2 * j - j) ^ j(也可以說(shuō)i % 2 * i/64 - i/64 或者藏青色的傾斜線(xiàn))大于 1 或小于 -1。
為了將這個(gè)地方講清楚,這里有一些Javascript控制臺(tái)的輸出,0 或者 -2 意味著結(jié)果是偶數(shù),1 則是奇數(shù)。
1 ^ 1 // 0 - even p 1.1 ^ 1.1 // 0 - even p 0.9 ^ 1 // 1 - odd . 0 ^ 1 // 1 - odd . -1 ^ 1 // -2 - even p -1.1 ^ 1.1 // -2 - even p如果我們觀(guān)察下我們的圖形,可以看出原點(diǎn)右邊的斜線(xiàn)大部分都是大于 1 或者小于 -1(幾乎沒(méi)有偶數(shù),或者說(shuō)幾乎沒(méi)有 p),且越靠后(靠近原點(diǎn))越如此。第 16 行幾乎介于 2 和 -2 之間。第 16 行之后,我們可以看到圖形是另外一種模式。
16 行之后 j 超過(guò)了 2,使得結(jié)果發(fā)生了變化?,F(xiàn)在當(dāng)藏青色的斜線(xiàn)大于 2 ,小于 -2 ,或者在1和-1之間且不等于的時(shí)候,我們將會(huì)得到一個(gè)偶數(shù)。這也是為什么在 17 行之后我們會(huì)在一行內(nèi)看到兩組和兩組以上的 p。
如果你仔細(xì)看動(dòng)圖的最底部幾行,你會(huì)發(fā)現(xiàn)這幾行不符合上面的規(guī)則,圖表曲線(xiàn)看起來(lái)起伏非常大。
現(xiàn)在讓我們把 + n/DELAY 加回來(lái)。在代碼里我們可以看到 n 的初始值是 8 (初始是 1 ,但是每次定時(shí)器被調(diào)用時(shí)就加 7),它會(huì)在每次執(zhí)行定時(shí)器時(shí)增加 7。
當(dāng) n 變成 64,圖形會(huì)變成如下樣子。
可以注意到,j 總是 ~1(這里的 ~ 是近似的意思),但是現(xiàn)在紅斜線(xiàn)的左半邊位于 62-63 區(qū)間的值無(wú)限趨近于 0,紅斜線(xiàn)的右半邊位于 63-64 則無(wú)限趨近與 1。因?yàn)槲覀兊淖址?4到62的順序排列,那么我們可以猜測(cè)斜線(xiàn)的 63-64 部分(1^1=0 是偶數(shù))添加的是一段 p,左邊 62-63 部分(1^0=1 是奇數(shù))添加的是一段 .。就像普通的英語(yǔ)單詞一樣,從左到右的添加上。
用 HTML 渲染出來(lái)的話(huà),將會(huì)看到下圖(你可以自己在 codepen 改變 n 來(lái)觀(guān)看效果)。這和我們的預(yù)期一致。
這一時(shí)刻 p 的數(shù)量已經(jīng)增長(zhǎng)了一定的數(shù)量。例如第一行里面就有一半的值是偶數(shù),從現(xiàn)在起,一大段的p 和 s 將移動(dòng)他們的位置。
為了說(shuō)明這一點(diǎn),我們可以看到當(dāng) n 在下一個(gè)定時(shí)器里增加了 7 時(shí),圖形就會(huì)有稍微的變化
注意,第一行的斜線(xiàn)(在 64 附近)已經(jīng)稍微移動(dòng)了 1 小格,假設(shè) 4 個(gè)方格代表 128 個(gè)字符,1 個(gè)方格 相當(dāng)于 32 個(gè)字符,那么 1 個(gè)小格則相當(dāng)于 32/5=6.4 個(gè)字符(大約)。正如下圖所示,我們可以看到第一行實(shí)際上向右移動(dòng)了 7 個(gè)字符。
最后一個(gè)例子。就是當(dāng)定時(shí)器被調(diào)用超過(guò) 7 次時(shí)(n 等于 64+9x7)會(huì)發(fā)生什么。
對(duì)于第一行,j 還等于 1?,F(xiàn)在紅斜線(xiàn)的上部分在 64 左右的值趨向于 2,下部分趨向于 1。這個(gè)圖片將會(huì)翻轉(zhuǎn),因?yàn)楝F(xiàn)在 1^2 = 3 是奇數(shù)-輸出. 而 1^1 = 0 是偶數(shù)- 輸出p。所以我們預(yù)期在一大段 p 之后會(huì)是一大段 .。
他會(huì)這么渲染。
自此,圖形將會(huì)以這種形式無(wú)限循環(huán)下去。
我希望我解釋清楚了。我不認(rèn)為自己有能力寫(xiě)出這樣的代碼,但是我很享受理解它的過(guò)程。
iKcamp原創(chuàng)新書(shū)《移動(dòng)Web前端高效開(kāi)發(fā)實(shí)戰(zhàn)》已在亞馬遜、京東、當(dāng)當(dāng)開(kāi)售。
滬江Web前端上海團(tuán)隊(duì)招聘【W(wǎng)eb前端架構(gòu)師】,有意者簡(jiǎn)歷至:zhouyao@hujiang.com
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/88441.html
摘要:前端日?qǐng)?bào)精選一行代碼的逆向工程譯只需四個(gè)步驟使用實(shí)現(xiàn)頁(yè)面過(guò)渡動(dòng)畫(huà)如何實(shí)現(xiàn)一個(gè)基于的模板引擎解剖組件的多種寫(xiě)法與演進(jìn)深入理解筆記擴(kuò)展對(duì)象的功能性中文基礎(chǔ)系列一之實(shí)現(xiàn)抽獎(jiǎng)刮刮卡橡皮擦掘金小游戲個(gè)人文章和最常用的特征眾成翻譯常用語(yǔ)法總 2017-08-08 前端日?qǐng)?bào) 精選 一行 JavaScript 代碼的逆向工程【譯】只需四個(gè)步驟:使用 React 實(shí)現(xiàn)頁(yè)面過(guò)渡動(dòng)畫(huà)如何實(shí)現(xiàn)一個(gè)基于 DOM...
摘要:花點(diǎn)時(shí)間搞清楚中的分號(hào)規(guī)則吧不管你喜歡結(jié)尾帶分號(hào)或省略分號(hào)的模式分號(hào)允許的場(chǎng)景分號(hào)一般允許出現(xiàn)在大部分語(yǔ)句的末尾,比如等栗子僅有一個(gè)分號(hào)可以表示空語(yǔ)句在中合法,比如可解析為三個(gè)空語(yǔ)句空語(yǔ)句可用于輔助產(chǎn)生語(yǔ)法合法的解析結(jié)果,如如果沒(méi)有末尾的 花點(diǎn)時(shí)間搞清楚JS中的分號(hào)規(guī)則吧~~~不管你喜歡結(jié)尾帶分號(hào)或省略分號(hào)的模式 分號(hào)允許的場(chǎng)景 分號(hào)一般允許出現(xiàn)在大部分語(yǔ)句(statement)的末尾...
摘要:跟非常相似,但是在開(kāi)始嘗試你第一個(gè)之前,也需要了解兩者之間的一些差異。推薦的方式是使用提供的。能用到組件中的或者上以啟用這個(gè)組件的觸摸事件。 華翔,Web前端開(kāi)發(fā)工程師著作權(quán)歸作者所有,轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán)。 showImg(https://segmentfault.com/img/bVUliz?w=640&h=235); React-Native已經(jīng)誕生有兩年左右了,自從適配了An...
摘要:前端日?qǐng)?bào)精選從零學(xué)習(xí)技術(shù)棧新版本及簡(jiǎn)介石墨表格之應(yīng)用實(shí)戰(zhàn)一道面試題目引發(fā)的思考新為帶來(lái)的性能變化中文第期前端部署采坑記個(gè)最基本的面試問(wèn)題及答案上插件開(kāi)發(fā)簡(jiǎn)介一開(kāi)發(fā)入門(mén)掘金插件開(kāi)發(fā)簡(jiǎn)介二如何添加瀏覽器擴(kuò)展白名單掘金層疊相關(guān)知識(shí)指北掘 2017-09-09 前端日?qǐng)?bào) 精選 從零學(xué)習(xí)React技術(shù)棧:React 新版本及 ES6 簡(jiǎn)介石墨表格之 Web Worker 應(yīng)用實(shí)戰(zhàn)一道面試題目引發(fā)...
閱讀 3086·2023-04-26 00:53
閱讀 3536·2021-11-19 09:58
閱讀 1700·2021-09-29 09:35
閱讀 3290·2021-09-28 09:46
閱讀 3869·2021-09-22 15:38
閱讀 2698·2019-08-30 15:55
閱讀 3016·2019-08-23 14:10
閱讀 3831·2019-08-22 18:17