摘要:僅在幾年以前,僅有少數(shù)的程序員知道函數(shù)式編程是什么。函數(shù)式編程是聲明性的而不是命令式的應(yīng)用狀態(tài)流經(jīng)純函數(shù)中。函數(shù)式編程是一種編程模式。在理解軟件是如何使用函數(shù)式編程構(gòu)建時(shí),理解函數(shù)組合是非常重要的一步。不可變性是函數(shù)式編程的核心概念。
函數(shù)式編程已然變成了一個(gè)javascript語(yǔ)言中一個(gè)非常熱門(mén)的話(huà)題。僅在幾年以前,僅有少數(shù)的js程序員知道函數(shù)式編程是什么。但是在過(guò)去三年中,我所見(jiàn)過(guò)的每個(gè)大型應(yīng)用代碼庫(kù)里都使用了函數(shù)式編程概念。
函數(shù)式編程(經(jīng)??s寫(xiě)為FP)是通過(guò)組合純函數(shù),避免共享狀態(tài)、可變數(shù)據(jù)、和副作用來(lái)構(gòu)建軟件的過(guò)程。函數(shù)式編程是聲明性的而不是命令式的,應(yīng)用狀態(tài)流經(jīng)純函數(shù)中。相比于面向?qū)ο缶幊蹋渲械膽?yīng)用狀態(tài)經(jīng)常是共享的,并且和方法一起定義在一些對(duì)象中。
函數(shù)式編程是一種編程模式。意味著它是一種基于一些基本原理和定義原則(如上所列)來(lái)思考軟件構(gòu)造的方式。其它的編程模式還包括面向?qū)ο缶幊毯瓦^(guò)程式編程。
相比于命令式的和面向?qū)ο笫降拇a,函數(shù)式的代碼趨向于更簡(jiǎn)潔、更加可預(yù)言的、更容易測(cè)試。但如果你還不熟悉函數(shù)式編程以及它相關(guān)聯(lián)的一些基本模式,函數(shù)式的代碼看起來(lái)會(huì)更加緊湊,與之相關(guān)的文獻(xiàn)對(duì)于初學(xué)者來(lái)說(shuō)也會(huì)比較費(fèi)解。
如果你開(kāi)始谷歌搜索函數(shù)式編程時(shí),你將很快會(huì)遇到大量的非常專(zhuān)業(yè)的學(xué)術(shù)性術(shù)語(yǔ),這對(duì)初學(xué)者來(lái)說(shuō)是非常嚇人的。說(shuō)它有學(xué)習(xí)曲線(xiàn)就太輕描淡寫(xiě)了。但如果你已經(jīng)寫(xiě)過(guò)js代碼經(jīng)驗(yàn),很有可能你已經(jīng)在真實(shí)的軟件中使用了大量的函數(shù)式編程概念和工具。
不要讓所有的新詞匯嚇走你。它通常比聽(tīng)起來(lái)更簡(jiǎn)單。最難的部分是理解所有不熟悉的詞匯。上面那些看似無(wú)關(guān)緊要的定義包含許多概念,這些概念需要在你掌握函數(shù)式編程的含義之前理解:
純函數(shù)
函數(shù)組合
避免共享的狀態(tài)
避免改變狀態(tài)
避免副作用
換句話(huà)說(shuō),如果你想知道函數(shù)式編程在實(shí)踐中代表著什么含義,那么你不得不從理解這些核心概念開(kāi)始。
純函數(shù):
給定相同的輸入,總是返回相同的輸出
沒(méi)有副作用
在函數(shù)式編程中,純函數(shù)有很多重要的特性。包括引用透明性(你可以將一個(gè)函數(shù)調(diào)用替換成它的結(jié)果值而不會(huì)改變程序的意義)??砷喿x什么是純函數(shù)了解更多。
函數(shù)組合:
函數(shù)組合是將兩個(gè)或更多的函數(shù)組合成一個(gè)新函數(shù)或者執(zhí)行一些計(jì)算的過(guò)程。例如,在javascript中,組成 f . g (.點(diǎn)代表組成)等價(jià)于f(g(x))。在理解軟件是如何使用函數(shù)式編程構(gòu)建時(shí),理解函數(shù)組合是非常重要的一步。
可閱讀什么是函數(shù)組合了解更多。
共享狀態(tài):
共享狀態(tài)是任意變量、對(duì)象或者是內(nèi)存空間其存在于共享的作用域中,或者是作為一個(gè)對(duì)象的屬性在各個(gè)作用域中傳遞。共享作用域包含全局作用域或者是閉包。經(jīng)常,在面向?qū)ο缶幊讨?,在作用域中共享?duì)象是通過(guò)將其添加為其他對(duì)象的屬性。
例如,一個(gè)計(jì)算機(jī)游戲可能有一個(gè)主要的游戲?qū)ο?,該?duì)象包含一些任務(wù)角色和游戲項(xiàng)目作為它擁有的屬性。函數(shù)式編程避免共享的狀態(tài)—相反它依賴(lài)不可變的數(shù)據(jù)結(jié)構(gòu)和純計(jì)算從已有的數(shù)據(jù)中獲取新數(shù)據(jù)。
更多關(guān)于函數(shù)式的軟件是如何處理應(yīng)用狀態(tài)的,可參考10個(gè)關(guān)于獲得更好的redux 架構(gòu)的技巧
共享狀態(tài)的問(wèn)題在于,為了理解一個(gè)函數(shù)的效果,你必須知道每個(gè)共享變量在函數(shù)中怎么使用和產(chǎn)生影響的整個(gè)歷史。
想象一下你有一個(gè)用戶(hù)對(duì)象需要保存。你的saveUser()函數(shù)發(fā)送一個(gè)API請(qǐng)求到服務(wù)端。在這個(gè)請(qǐng)求發(fā)送過(guò)程中,用戶(hù)更改用戶(hù)頭像:updateAvatar()并觸發(fā)了另一個(gè)saveUser()請(qǐng)求。在保存時(shí),服務(wù)器發(fā)送回一個(gè)權(quán)威的用戶(hù)對(duì)象用于替換在內(nèi)存中的數(shù)據(jù)以同步發(fā)生在服務(wù)端的改變或者響應(yīng)其它的API請(qǐng)求。
不幸的是,第二個(gè)響應(yīng)結(jié)果比第一個(gè)響應(yīng)結(jié)果在到達(dá),所以當(dāng)?shù)谝粋€(gè)(現(xiàn)在是過(guò)時(shí)的)響應(yīng)到達(dá)時(shí),新的用戶(hù)頭像將會(huì)在內(nèi)存中被清除掉并用舊的頭像替代。這是一個(gè)競(jìng)態(tài)條件的例子——是一個(gè)關(guān)于共享狀態(tài)存在的一個(gè)非常普遍的缺陷。
另外一個(gè)關(guān)于共享狀態(tài)存在的普遍問(wèn)題是改變函數(shù)的調(diào)用順序會(huì)引發(fā)一連串的失敗。因?yàn)樽饔迷诠蚕頎顟B(tài)的函數(shù)是具有時(shí)間依賴(lài)性的。
// With shared state, the order in which function calls are made // changes the result of the function calls. const x = { val: 2 }; const x1 = () => x.val += 1; const x2 = () => x.val *= 2; x1(); x2(); console.log(x.val); // 6 // This example is exactly equivalent to the above, except... const y = { val: 2 }; const y1 = () => y.val += 1; const y2 = () => y.val *= 2; // ...the order of the function calls is reversed... y2(); y1(); // ... which changes the resulting value: console.log(y.val); // 5
當(dāng)你避免共享狀態(tài),時(shí)間和函數(shù)調(diào)用順序不會(huì)改變調(diào)用函數(shù)的結(jié)果。利用純函數(shù),給定相同的輸入,你將始終得到相同的輸出。這使得函數(shù)調(diào)用完全獨(dú)立于其他的函數(shù)調(diào)用,可徹底簡(jiǎn)化更改和重構(gòu)。一個(gè)函數(shù)中的改變或者是函數(shù)調(diào)用的時(shí)間都不會(huì)影響和破壞程序的其它部分。
const x = { val: 2 }; const x1 = x => Object.assign({}, x, { val: x.val + 1}); const x2 = x => Object.assign({}, x, { val: x.val * 2}); console.log(x1(x2(x)).val); // 5 const y = { val: 2 }; // Since there are no dependencies on outside variables, // we don"t need different functions to operate on different // variables. // this space intentionally left blank // Because the functions don"t mutate, you can call these // functions as many times as you want, in any order, // without changing the result of other function calls. x2(y); x1(y); console.log(x1(x2(y)).val); // 5
在上面的例子中,我們使用Object.assign()并傳遞一個(gè)空對(duì)象作為第一個(gè)參數(shù)用來(lái)拷貝x的屬性而不是直接修改它。在這種情況下,這就相當(dāng)于不利用Object.assign()方法,從零開(kāi)始簡(jiǎn)單地創(chuàng)建一個(gè)新對(duì)象。但這在javascript中是一種非常常見(jiàn)的模式為已存在的狀態(tài)創(chuàng)建拷貝副本而不是直接修改已有的狀態(tài)值,就如第一個(gè)例子所演示的一樣。
如果你仔細(xì)看一下這個(gè)例子中的console.log()語(yǔ)句,你應(yīng)該會(huì)發(fā)現(xiàn)我前面提到過(guò)的一些概念:函數(shù)組合。回想一下前面的內(nèi)容,函數(shù)組合應(yīng)該是像這樣:f(g(x))。在這個(gè)例子中,我們分別將f()和g()替換為想x1()和x2()成為組合x1?. x2。
當(dāng)然,如果你改變組合的順序,輸出將會(huì)改變。運(yùn)算順序是有影響的。f(g(x))不總是等于g(f(x)),但是在函數(shù)之外的變量發(fā)生了什么變得不再重要了,這才是重要的事。如果使用非純函數(shù),那么久不可能完全理解一個(gè)函數(shù)做了什么,除非你了解函數(shù)使用和影響的每個(gè)變量的整個(gè)歷史。
移除掉函數(shù)調(diào)用的時(shí)間依賴(lài)性,你會(huì)消除掉一整類(lèi)的潛在的bug。
不變性:
不可變的對(duì)象是指一個(gè)對(duì)象一旦創(chuàng)建后不能對(duì)其修改。相反,可變的對(duì)象是指對(duì)象創(chuàng)建后可對(duì)其進(jìn)行修改。
不可變性是函數(shù)式編程的核心概念。因?yàn)槿绻鄙偎?,程序中的?shù)據(jù)流將會(huì)有損耗。狀態(tài)歷史被遺棄的話(huà),奇怪的bug將會(huì)蔓延到軟件中。關(guān)于更多不可變性的意義,可參考The Dao of Immutability。
在javascript中,不將const和不可變性混為一談是很重要的。const是變量名綁定,變量創(chuàng)建后不能重新賦值。const不能創(chuàng)建不可變的對(duì)象。你不可以改變對(duì)象的引用指向,但是你仍可以改變對(duì)象上的屬性值。也就是說(shuō),用const創(chuàng)建的綁定是可變的而不是不可變的。
不可變的對(duì)象是完全不可以改變的。你可以通過(guò)深度凍結(jié)對(duì)象做到一個(gè)值真正地不可變。JavaScript中有一個(gè)方法可以?xún)鼋Y(jié)一個(gè)對(duì)象的一級(jí)深度。
const a = Object.freeze({ foo: "Hello", bar: "world", baz: "!" }); a.foo = "Goodbye"; // Error: Cannot assign to read only property "foo" of object Object
但是,凍結(jié)對(duì)象只是表面上的不可變。例如,下面的對(duì)象是可變的:
const a = Object.freeze({ foo: { greeting: "Hello" }, bar: "world", baz: "!" }); a.foo.greeting = "Goodbye"; console.log(`${ a.foo.greeting }, ${ a.bar }${a.baz}`);
正如你所看見(jiàn)的,一個(gè)凍結(jié)對(duì)象的頂層的簡(jiǎn)單屬性是不可以改變的,但是如果任意一個(gè)屬性是對(duì)象類(lèi)型(包含數(shù)組等),那么它仍然是可以修改的。因此,即使是凍結(jié)的對(duì)象也不是不可變的,除非你遍歷整個(gè)對(duì)象樹(shù)并凍結(jié)每一個(gè)對(duì)象類(lèi)型屬性。
在許多函數(shù)式編程語(yǔ)言中,有一些特殊的不可變數(shù)據(jù)結(jié)構(gòu)—trie data structures(讀作‘tree’)。它們是有效的深度凍結(jié),意味著任何屬性都不能被更改,無(wú)論它位于對(duì)象的那一層級(jí)上。
針對(duì)對(duì)象的所有部分,Tries 使用共享結(jié)構(gòu)來(lái)共享引用內(nèi)存位置。在對(duì)象被一個(gè)操作拷貝之后,它們?nèi)匀皇俏幢桓淖兊?。Tries使用了更少的內(nèi)存,使得一些操作在性能上有很大提升。
例如,你可以在對(duì)象樹(shù)上的根部使用身份對(duì)照用于對(duì)比。如果身份相同,那就無(wú)需遍歷整棵樹(shù)來(lái)檢查差異性。
在JavaScript中還有一些庫(kù)利用了tries的有點(diǎn),包括immutable-js和mori
我已經(jīng)嘗試過(guò)上面兩種,并趨向于在需要大量不可變狀態(tài)的大項(xiàng)目中使用Imuutable.js。更多相關(guān)內(nèi)容請(qǐng)?jiān)斠?jiàn)10個(gè)關(guān)于獲得更好的redux 架構(gòu)的技巧。
副作用:
副作用是指任意的應(yīng)用狀態(tài)變化在程序調(diào)用的外面都是可見(jiàn)的而不是作為他的返回值。副作用包括:
更改任意的外部變量和對(duì)象屬性(如全局變量,或位于父函數(shù)作用域鏈中的變量)
輸出日志到console
在屏幕上寫(xiě)
寫(xiě)文件
寫(xiě)數(shù)據(jù)到網(wǎng)絡(luò)
觸發(fā)任意外部處理
調(diào)用任何包含副作用的其它函數(shù)
副作用在函數(shù)式編程中大多被避免可使得程序的效果更容易被理解和測(cè)試。
Haskell 和其它函數(shù)式語(yǔ)言經(jīng)常使用monads從純函數(shù)中隔離和封裝副作用。monads主題的內(nèi)容足夠?qū)懸槐緯?shū),所以我們將它放在后面。
你現(xiàn)在只需要知道的是副作用需要在你軟件剩下的部分中隔離出來(lái)。如果你保持副作用從剩下的程序邏輯中隔離出,那你的軟件將會(huì)變得更加容易擴(kuò)展、重構(gòu)、調(diào)試和維護(hù)。
這就是為什么大多數(shù)前端框架為什么鼓勵(lì)用戶(hù)分開(kāi)管理狀態(tài)和組件渲染,弱耦合模塊。
利用高階函數(shù)達(dá)到可重用性
函數(shù)式編程趨向于重用一套通用的函數(shù)式的實(shí)用工具來(lái)處理數(shù)據(jù)。面向?qū)ο缶幊腾呄蛴趯⒎椒ê蛿?shù)據(jù)都放在對(duì)象中。這些同地協(xié)作的方法僅僅操作它們被設(shè)計(jì)好的期望操作的數(shù)據(jù)類(lèi)型。而且經(jīng)常是一些僅包含在特定對(duì)象實(shí)例中的數(shù)據(jù)。
在函數(shù)式編程中,任意數(shù)據(jù)類(lèi)型都是場(chǎng)公平競(jìng)爭(zhēng)的游戲。相同的map工具可映射在對(duì)象、字符串、數(shù)字、或者任何其它類(lèi)型數(shù)據(jù)上。因?yàn)樗邮芤粋€(gè)函數(shù)作為參數(shù)并適當(dāng)?shù)靥幚斫o定的數(shù)據(jù)類(lèi)型。FP使用高階函數(shù)實(shí)現(xiàn)了它的通用工具詭計(jì)。
JavaScript具有一級(jí)函數(shù),這允許我們將函數(shù)作為數(shù)據(jù)賦值給變量,傳遞給其它函數(shù),從函數(shù)中返回,等等。。。
高階函數(shù)是采用一個(gè)函數(shù)作為參數(shù),返回一個(gè)函數(shù),或者兩者兼具的一個(gè)函數(shù)。高階函數(shù)常用于:
抽取或者隔離動(dòng)作,影響或者使用回調(diào)函數(shù),promise, monads等的異步流控制
創(chuàng)建可作用于各種各樣數(shù)據(jù)類(lèi)型的實(shí)用工具
部分應(yīng)用一個(gè)函數(shù)到它的參數(shù)或者創(chuàng)建一個(gè)柯里化函數(shù)達(dá)到重用或者函數(shù)組合的目的。
接受一系列函數(shù)并返回這些輸入函數(shù)的一些組合
Containers, Functors, Lists, and Streams
functor是指可用于映射的東西。換句話(huà)說(shuō),它是一個(gè)容器,包含一個(gè)可應(yīng)用一個(gè)函數(shù)到它內(nèi)部數(shù)據(jù)的接口。當(dāng)你看見(jiàn)functor這個(gè)詞時(shí),你應(yīng)該想到可映射的(mappable)。
前面我們學(xué)習(xí)了相同的map工具可作用于各種類(lèi)型的數(shù)據(jù)類(lèi)型。它通過(guò)映射操作和一個(gè)functor API一起工作完成目的。map()使用的重要流控制操作利用了接口的優(yōu)點(diǎn)。從Array.prototype.map()情況來(lái)看,數(shù)組是container,但是其它數(shù)據(jù)結(jié)構(gòu)也可以是functors,只要它們提供映射API。
讓我們看下Array.prototype.map()是怎么允許你從映射工具中抽取數(shù)據(jù)類(lèi)型使得map()可以在任何數(shù)據(jù)類(lèi)型下都是可用的。我們將創(chuàng)建一個(gè)簡(jiǎn)單的double()映射,它只是簡(jiǎn)單的將傳進(jìn)來(lái)值乘以2:
const double = n => n * 2; const doubleMap = numbers => numbers.map(double); console.log(doubleMap([2, 3, 4])); // [ 4, 6, 8 ]
如果我們希望操作游戲中的數(shù)據(jù),將游戲所獲得的點(diǎn)數(shù)翻倍該怎么辦呢?所有我們需要做的是對(duì)傳遞給map()的double函數(shù)做一點(diǎn)微小的變動(dòng),然后所有的東西都會(huì)正常工作:
const double = n => n.points * 2; const doubleMap = numbers => numbers.map(double); console.log(doubleMap([ { name: "ball", points: 2 }, { name: "coin", points: 3 }, { name: "candy", points: 4} ])); // [ 4, 6, 8 ]
使用抽象(像functors和高階函數(shù)這樣為了使用通用的實(shí)用工具函數(shù)來(lái)操作任意數(shù)量的不同數(shù)據(jù)類(lèi)型)的概念對(duì)函數(shù)式編程是十分重要的,你將會(huì)看到一個(gè)類(lèi)似的概念應(yīng)用在各種不同途徑
*隨著時(shí)間表示的列表是流*
所有現(xiàn)在你需要理解就是數(shù)組和functors不是唯一的方式,讓容器這個(gè)概念和容器中的值來(lái)使用。比如,一個(gè)數(shù)組僅僅是一列東西。隨著時(shí)間表示的列表是流—所以你可以應(yīng)用相同類(lèi)型的工具來(lái)處理到來(lái)的事件流—這是一些當(dāng)你利用FP開(kāi)始構(gòu)建真實(shí)的軟件時(shí)經(jīng)??匆?jiàn)的東西。
聲明式 VS 命令式
函數(shù)式編程是聲明式模式,意味著程序的邏輯的表達(dá)無(wú)需明確的流控制的描述。
命令式程序花費(fèi)大量的代碼描述具體的步驟以獲取期望的結(jié)果—流控制:如何做。
聲明式程序抽象出流控制過(guò)程而不是花費(fèi)大量的代碼描述數(shù)據(jù)流:做什么?怎么做(how)被抽象出來(lái)了。
舉個(gè)栗子,命令式的映射傳入一個(gè)數(shù)字?jǐn)?shù)組并返回一個(gè)每個(gè)數(shù)字都乘以2的新數(shù)組。
const doubleMap = numbers => { const doubled = []; for (let i = 0; i < numbers.length; i++) { doubled.push(numbers[i] * 2); } return doubled; }; console.log(doubleMap([2, 3, 4])); // [4, 6, 8]
聲明式的映射也是做同樣的事情,但是使用函數(shù)式的Array.prototype.map()工具將流控制抽象出來(lái),
這就允許你更加清楚地表達(dá)數(shù)據(jù)流。
const doubleMap = numbers => numbers.map(n => n * 2); console.log(doubleMap([2, 3, 4])); // [4, 6, 8]
命令式的代碼經(jīng)常地使用陳述。陳述是一段用于執(zhí)行一些動(dòng)作的代碼。經(jīng)常使用陳述的例子包含for, if, switch, throw等。
聲明式的代碼更對(duì)依賴(lài)于表達(dá)式。表達(dá)書(shū)是一段用來(lái)計(jì)算一些值得代碼片段。表達(dá)式經(jīng)常是結(jié)合一些函數(shù)調(diào)用、值和操作符求值產(chǎn)生結(jié)果值。
這些都是表達(dá)式的例子:
2 * 2 doubleMap([2, 3, 4]) Math.max(4, 3, 2)
在代碼中,你會(huì)看到一些表達(dá)式賦值給一些標(biāo)識(shí)符,從函數(shù)中返回出來(lái)或者傳遞給函數(shù)。在賦值、返回或者傳遞之前,表達(dá)式先被求值,然后結(jié)果值被使用。
結(jié)論
函數(shù)式編程主張:
純函數(shù)而不是共享狀態(tài)和副作用
基于可變數(shù)據(jù)的不可變性
基于命令式流控制的函數(shù)組合
大量的通用的,可重用的工具使用高階函數(shù)作用于多種數(shù)據(jù)類(lèi)型而不是只能在它們共同協(xié)作的數(shù)據(jù)上操作。
聲明式的代碼而不是命令式的代碼(做什么而非怎么做)
表達(dá)式而不是陳述
基于即時(shí)多態(tài)的容器和高階函數(shù)
ps:歡迎指正翻譯不正之處。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/96583.html
摘要:插件開(kāi)發(fā)前端掘金作者原文地址譯者插件是為應(yīng)用添加全局功能的一種強(qiáng)大而且簡(jiǎn)單的方式。提供了與使用掌控異步前端掘金教你使用在行代碼內(nèi)優(yōu)雅的實(shí)現(xiàn)文件分片斷點(diǎn)續(xù)傳。 Vue.js 插件開(kāi)發(fā) - 前端 - 掘金作者:Joshua Bemenderfer原文地址: creating-custom-plugins譯者:jeneser Vue.js插件是為應(yīng)用添加全局功能的一種強(qiáng)大而且簡(jiǎn)單的方式。插....
摘要:首次運(yùn)行代碼時(shí),會(huì)創(chuàng)建一個(gè)全局執(zhí)行上下文并到當(dāng)前的執(zhí)行棧中。執(zhí)行上下文的創(chuàng)建執(zhí)行上下文分兩個(gè)階段創(chuàng)建創(chuàng)建階段執(zhí)行階段創(chuàng)建階段確定的值,也被稱(chēng)為。 (關(guān)注福利,關(guān)注本公眾號(hào)回復(fù)[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實(shí)戰(zhàn)、面試指導(dǎo)) 本周正式開(kāi)始前端進(jìn)階的第一期,本周的主題是調(diào)用堆棧,,今天是第一天 本計(jì)劃一共28期,每期重點(diǎn)攻克一個(gè)面試重難點(diǎn),如果你還不了解本進(jìn)...
摘要:在嚴(yán)格模式下調(diào)用函數(shù)則不影響默認(rèn)綁定。回調(diào)函數(shù)丟失綁定是非常常見(jiàn)的。因?yàn)橹苯又付ǖ慕壎▽?duì)象,稱(chēng)之為顯示綁定。調(diào)用時(shí)強(qiáng)制把的綁定到上顯示綁定無(wú)法解決丟失綁定問(wèn)題。 (關(guān)注福利,關(guān)注本公眾號(hào)回復(fù)[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實(shí)戰(zhàn)、面試指導(dǎo)) 本周正式開(kāi)始前端進(jìn)階的第三期,本周的主題是this全面解析,今天是第9天。 本計(jì)劃一共28期,每期重點(diǎn)攻克一個(gè)面試重...
摘要:然而學(xué)習(xí)布局,你只要學(xué)習(xí)幾個(gè)手機(jī)端頁(yè)面自適應(yīng)解決方案布局進(jìn)階版附源碼示例前端掘金一年前筆者寫(xiě)了一篇手機(jī)端頁(yè)面自適應(yīng)解決方案布局,意外受到很多朋友的關(guān)注和喜歡。 十分鐘學(xué)會(huì) Fiddler - 后端 - 掘金一.Fiddler介紹 Fiddler是一個(gè)http抓包改包工具,fiddle英文中有欺騙、偽造之意,與wireshark相比它更輕量級(jí),上手簡(jiǎn)單,因?yàn)橹荒茏ttp和https數(shù)據(jù)...
摘要:使用異步編程,有一個(gè)事件循環(huán)。它作為面向?qū)ο缶幊痰奶娲桨?,其中?yīng)用狀態(tài)通常與對(duì)象中的方法搭配并共享。在用面向?qū)ο缶幊虝r(shí)遇到不同的組件競(jìng)爭(zhēng)相同的資源的時(shí)候,更是如此。 翻譯:瘋狂的技術(shù)宅原文:https://www.indeed.com/hire/i... 本文首發(fā)微信公眾號(hào):jingchengyideng歡迎關(guān)注,每天都給你推送新鮮的前端技術(shù)文章 不管你是面試官還是求職者,里面...
閱讀 1252·2021-11-15 18:00
閱讀 1847·2021-10-08 10:15
閱讀 872·2021-09-04 16:48
閱讀 2467·2021-09-04 16:48
閱讀 1364·2019-08-29 18:40
閱讀 1027·2019-08-29 13:08
閱讀 3065·2019-08-26 14:06
閱讀 1184·2019-08-26 13:35