摘要:嵌套函數(shù)在一個(gè)函數(shù)中創(chuàng)建另一個(gè)函數(shù),稱為嵌套。這在很容易實(shí)現(xiàn)嵌套函數(shù)可以訪問外部變量,幫助我們很方便地返回組合后的全名。更有趣的是,嵌套函數(shù)可以作為一個(gè)新對(duì)象的屬性或者自己本身被。
來源于 現(xiàn)代JavaScript教程
閉包章節(jié)
中文翻譯計(jì)劃
本文很清晰地解釋了閉包是什么,以及閉包如何產(chǎn)生,相信你看完也會(huì)有所收獲
關(guān)鍵字
Closure 閉包
Lexical Environment 詞法環(huán)境
Environment Record 環(huán)境記錄
outer Lexical Environment 外部詞法環(huán)境
global Lexical Environment 全局語法環(huán)境
JavaScript 是一個(gè) function-oriented(直譯:面向函數(shù))的語言,這個(gè)特性為我們帶來了很大的操作自由。函數(shù)只需創(chuàng)建一次,賦值到一個(gè)變量,或者作為參數(shù)傳入另一個(gè)函數(shù)然后在一個(gè)全新的環(huán)境調(diào)用。
函數(shù)可以訪問它外部的變量,是一個(gè)常用 feature。
但是當(dāng)外部變量改變時(shí)會(huì)發(fā)生什么?函數(shù)會(huì)獲取最新的值,還是函數(shù)創(chuàng)建當(dāng)時(shí)的值?
還有一個(gè)問題,當(dāng)函數(shù)被傳入其他地方再調(diào)用……他能訪問那個(gè)地方的外部變量嗎?
不同語言的表現(xiàn)有所不同,下面我們研究一下 JavaScript 中的表現(xiàn)。
兩個(gè)問題我們先思考下面兩種情況,看完這篇文章你就可以回答這兩個(gè)問題,更復(fù)雜的問題也不在話下。
sayHi 函數(shù)使用了外部變量 name。函數(shù)運(yùn)行時(shí),會(huì)使用兩個(gè)值中的哪個(gè)?
let name = "John"; function sayHi() { alert("Hi, " + name); } name = "Pete"; sayHi(); // "John" 還是 "Pete"?
這個(gè)情況不論是瀏覽器端還是服務(wù)器端都很常見。函數(shù)很可能在它創(chuàng)建一段時(shí)間后才執(zhí)行,例如等待用戶操作或者網(wǎng)絡(luò)請求。
問題是:函數(shù)是否會(huì)選擇變量最新的值呢?
makeWorker 函數(shù)創(chuàng)建并返回了另一個(gè)函數(shù)。這個(gè)新函數(shù)可以在任何地方調(diào)用。他會(huì)訪問創(chuàng)建時(shí)的變量還是調(diào)用時(shí)的變量呢?
function makeWorker() { let name = "Pete"; return function() { alert(name); }; } let name = "John"; // 創(chuàng)建函數(shù) let work = makeWorker(); // 調(diào)用函數(shù) work(); // "Pete"(創(chuàng)建時(shí))還是 "John"(調(diào)用時(shí))?Lexical Environment(詞法環(huán)境)
要理解里面發(fā)生了什么,必須先明白“變量”到底是什么。
在 JavaScript 里,任何運(yùn)行的函數(shù)、代碼塊、整個(gè) script 都會(huì)關(guān)聯(lián)一個(gè)被稱為 Lexical Environment (詞法環(huán)境) 的對(duì)象。
Lexical Environment 對(duì)象包含兩個(gè)部分:(譯者:這里是重點(diǎn))
Environment Record(環(huán)境記錄)是一個(gè)以全部局部變量為屬性的對(duì)象(以及其他如 this 值的信息)。
對(duì) outer lexical environment(外部詞法環(huán)境)的引用,通常關(guān)聯(lián)詞法上的外面一層代碼(花括號(hào)外一層)。
所以,“變量”就是內(nèi)部對(duì)象 Environment Record 的一個(gè)屬性。要獲取或改變一個(gè)對(duì)象,意味著獲取改變 Lexical Environment 的屬性。
例如在這段簡單的代碼中,只有一個(gè) Lexical Environment:
這就是所謂 global Lexical Environment(全局語法環(huán)境),對(duì)應(yīng)整個(gè) script。對(duì)于瀏覽端,整個(gè) 標(biāo)簽共享一個(gè)全局環(huán)境。
(譯者:這里是重點(diǎn))
上圖中,正方形代表 Environment Record(變量儲(chǔ)存點(diǎn)),箭頭代表一個(gè)外部引用。global Lexical Environment 沒有外部引用,所以指向 null。
下圖展示 let 變量的工作機(jī)制:
右邊的正方形描述 global Lexical Environment 在執(zhí)行中如何改變:
腳本開始運(yùn)行,Lexical Environment 為空。
let phrase 定義出現(xiàn)了。因?yàn)闆]有賦值所以儲(chǔ)存為 undefined 。
phrase 被賦值。
phrase 被賦新值。
看起來很簡單對(duì)不對(duì)?
總結(jié):
變量是一個(gè)特殊內(nèi)部對(duì)象的屬性,關(guān)聯(lián)于執(zhí)行時(shí)的塊、函數(shù)、script 。
對(duì)變量的操作實(shí)際上是對(duì)這個(gè)對(duì)象屬性的操作。
Function Declaration(函數(shù)聲明)Function Declaration 與 let 不同,并非處理于被執(zhí)行的時(shí)候,而是(譯者注:意思就是全局詞法環(huán)境創(chuàng)建時(shí)處理函數(shù)聲明)Lexical Environment 創(chuàng)建的時(shí)候。對(duì)于 global Lexical Environment,意味著 script 開始運(yùn)行的時(shí)候。
這就是函數(shù)可以在定義前調(diào)用的原因。
以下代碼 Lexical Environment 開始時(shí)非空。因?yàn)橛?say 函數(shù)聲明,之后又有了 let 聲明的 phrase:
Inner and outer Lexical Environment(內(nèi)部詞法環(huán)境和外部詞法環(huán)境)調(diào)用 say() 的過程中,它使用了外部變量,一起看看這里面發(fā)生了什么。
(譯者:這里是重點(diǎn))
函數(shù)運(yùn)行時(shí)會(huì)自動(dòng)創(chuàng)建一個(gè)新的函數(shù) Lexical Environment。這是所有函數(shù)的通用規(guī)則。這個(gè)新的 Lexical Environment 用于當(dāng)前運(yùn)行函數(shù)的存放局部變量和形參。
箭頭標(biāo)記的是執(zhí)行 say("John") 時(shí)的 Lexical Environment :
函數(shù)調(diào)用過程中,可以看到兩個(gè) Lexical Environment(譯者注:就是兩個(gè)長方形):里面的是函數(shù)調(diào)用產(chǎn)生的,外面的是全局的:
內(nèi)層 Lexical Environment 對(duì)應(yīng)當(dāng)前執(zhí)行的 say。它只有一個(gè)變量:函數(shù)實(shí)參 name。我們調(diào)用了 say("John"),所以 name 的值是 "John"。
外層 Lexical Environment 是 global Lexical Environment。
內(nèi)層 Lexical Environment 的 outer 屬性指向外層 Lexical Environment。
代碼要訪問一個(gè)變量,首先搜索內(nèi)層 Lexical Environment ,接著是外層,再外層,直到鏈的結(jié)束。
如果走完整條鏈變量都找不到,在 strict mode 就會(huì)報(bào)錯(cuò)了。不使用 use strict 的情況下,對(duì)未定義變量的賦值,會(huì)創(chuàng)造一個(gè)新的全局變量。
下面一起看看變量搜索如何處理:
say 里的 alert 想要訪問 name,立即就能在當(dāng)前函數(shù)的 Lexical Environment 找到。
而局部變量不存在 phrase,所以要循著 outer 在全局變量里找到。
現(xiàn)在我們可以回答本章開頭的第一個(gè)問題了。
函數(shù)獲取外部變量當(dāng)前值
舊變量值不儲(chǔ)存在任何地方,函數(shù)需要他們的時(shí)候,它取得來源于自身或外部 Lexical Environment 的當(dāng)前值。(譯者注:就是引用值)
所以第一個(gè)問題的答案是 Pete:
let name = "John"; function sayHi() { alert("Hi, " + name); } name = "Pete"; // (*) sayHi(); // Pete
上述代碼的執(zhí)行流:
global Lexical Environment 存在 name: "John" 。
(*) 行中,全局變量修改了,現(xiàn)在成了這樣 name: "Pete" 。
say() 執(zhí)行的時(shí)候,取外部 name。此時(shí)在 global Lexical Environment 中已經(jīng)是 "Pete"。
一次調(diào)用,一個(gè) Lexical Environment
請注意,每當(dāng)一個(gè)函數(shù)運(yùn)行,就會(huì)創(chuàng)建一個(gè)新的 function Lexical Environment。
如果一個(gè)函數(shù)被多次調(diào)用,那么每次調(diào)用都會(huì)生成一個(gè)屬于當(dāng)前調(diào)用的全新 Lexical Environment,里面裝載著當(dāng)前調(diào)用的變量和實(shí)參。
Lexical Environment 是一個(gè)標(biāo)準(zhǔn)對(duì)象(specification object)嵌套函數(shù)
"Lexical Environment" 是一個(gè)標(biāo)準(zhǔn)對(duì)象(specification object),不能直接獲取或設(shè)置它,JavaScript 引擎也可能優(yōu)化它,拋棄未使用的變量來節(jié)省內(nèi)存或者作其他優(yōu)化,但是可見行為應(yīng)該如上面所述。
在一個(gè)函數(shù)中創(chuàng)建另一個(gè)函數(shù),稱為“嵌套”。這在 JavaScript 很容易實(shí)現(xiàn):
function sayHiBye(firstName, lastName) { // helper nested function to use below function getFullName() { return firstName + " " + lastName; } alert( "Hello, " + getFullName() ); alert( "Bye, " + getFullName() ); }
嵌套函數(shù) getFullName() 可以訪問外部變量,幫助我們很方便地返回組合后的全名。
更有趣的是,嵌套函數(shù)可以作為一個(gè)新對(duì)象的屬性或者自己本身被 return。這樣它們就能在其他地方使用,無論在哪里,它都能訪問同樣的外部變量。
一個(gè)構(gòu)造函數(shù)的例子:
// 構(gòu)造函數(shù)返回一個(gè)新對(duì)象 function User(name) { // 嵌套函數(shù)創(chuàng)造對(duì)象方法 this.sayHi = function() { alert(name); }; } let user = new User("John"); user.sayHi(); // 方法返回外部 "name"
一個(gè) return 函數(shù)的例子:
function makeCounter() { let count = 0; return function() { return count++; // has access to the outer counter }; } let counter = makeCounter(); alert( counter() ); // 0 alert( counter() ); // 1 alert( counter() ); // 2
我們接著研究 makeCounter。counter 函數(shù)每調(diào)用一次就會(huì)返回下一個(gè)數(shù)。這段代碼很簡單,但只要稍微修改,就能具有一定的實(shí)用性,例如偽隨機(jī)數(shù)生成器。
counter 內(nèi)部如何工作?
內(nèi)部函數(shù)運(yùn)行, count++ 中的變量由內(nèi)到外搜索:
嵌套函數(shù)局部變量……
外層函數(shù)……
直到全局變量。
第 2 步我們找到了 count。外部變量會(huì)直接在其所在的地方被修改。所以 count++ 檢索外部變量,并在該變量自己的 Lexical Environment 進(jìn)行 +1 操作。就像操作了 let count = 1 一樣。
這里需要思考兩個(gè)問題:
我們能通過 makeCounter 以外的方法重置 counter 嗎?
如果我們可以多次調(diào)用 makeCounter() ,返回了很多 counter 函數(shù),他們的 count 是獨(dú)立的還是共享的?
繼續(xù)閱讀前可以先嘗試思考一下。
...
ok ?
那我們開始揭曉謎底:
沒門。counter 是局部變量,不可能在外部直接訪問。
每次調(diào)用 makeCounter() 都會(huì)新建 Lexical Environment,每一個(gè)環(huán)境都有自己的 counter。所以不同 counter 里的 count 是獨(dú)立的。
一個(gè) demo :
function makeCounter() { let count = 0; return function() { return count++; }; } let counter1 = makeCounter(); let counter2 = makeCounter(); alert( counter1() ); // 0 alert( counter1() ); // 1 alert( counter2() ); // 0 (獨(dú)立)
現(xiàn)在你清楚明白了外部變量的情況,但是面對(duì)更復(fù)雜的情況仍然需要更深入地理解,讓我們進(jìn)入下一步吧。
Environment 細(xì)節(jié)對(duì) closure(閉包)有了初步了解之后,可以開始深入細(xì)節(jié)了。
下面是 makeCounter 例子的動(dòng)作分解,跟著看你就能理解一切了。注意,[[Environment]] 屬性我們之前尚未介紹。
腳本開始運(yùn)行,此時(shí)只存在 global Lexical Environment :
這時(shí)候只有 makeCounter 一個(gè)函數(shù),這是函數(shù)聲明,還未被調(diào)用。
所有函數(shù)都帶著一個(gè)隱藏屬性 [[Environment]] “誕生”。[[Environment]] 指向它們創(chuàng)建者的 Lexical Environment。是[[Environment]] 讓函數(shù)知道它“誕生”于什么環(huán)境。
makeCounter 創(chuàng)建于 global Lexical Environment,所以 [[Environment]] 指向它。
換句話說,Lexical Environment 在函數(shù)誕生時(shí)就“銘刻”在這個(gè)函數(shù)中。[[Environment]] 是指向 Lexical Environment 的隱藏函數(shù)屬性。
代碼繼續(xù)執(zhí)行,makeCounter() 登場。這是代碼運(yùn)行到 makeCounter() 瞬間的快照:
makeCounter() 調(diào)用時(shí),保存當(dāng)前變量和實(shí)參的 Lexical Environment 已經(jīng)被創(chuàng)建。
Lexical Environment 儲(chǔ)存 2 個(gè)東西:
帶有局部變量的 Environment Record。例子中 count 是唯一的局部變量(let count 被執(zhí)行的時(shí)候記錄)。
被綁定到函數(shù) [[Environment]] 的外部詞法引用。例子里 makeCounter 的 [[Environment]] 指向 global Lexical Environment。
所以這里有兩個(gè) Lexical Environment:全局,和 makeCounter(它的 outer 指向全局)。
在 makeCounter() 執(zhí)行的過程中,創(chuàng)建了一個(gè)嵌套函數(shù)。
這無關(guān)于函數(shù)創(chuàng)建使用的是 Function Declaration(函數(shù)聲明)還是 Function Expression(函數(shù)表達(dá)式)。所有函數(shù)都會(huì)得到一個(gè)指向他們創(chuàng)建時(shí) Lexical Environment 的 [[Environment]] 屬性。
這個(gè)嵌套函數(shù)的 [[Environment]] 是 makeCounter()(它的誕生地)的 Lexical Environment:
同樣注意,這一步是函數(shù)聲明而非調(diào)用。
代碼繼續(xù)執(zhí)行,makeCounter() 調(diào)用結(jié)束,內(nèi)嵌函數(shù)被賦值到全局變量 counter:
這個(gè)函數(shù)只有一行:return count++。
counter() 被調(diào)用,自動(dòng)創(chuàng)建一個(gè)空的 Lexical Environment。此函數(shù)無局部變量,但是 [[Environment]] 引用了外面一層,所以它可以訪問 makeCounter() 的變量。
要訪問變量,先檢索自己的 Lexical Environment(空),然后是 makeCounter() 的,最后是全局的。例子中在外層一層 Lexical Environment makeCounter 中發(fā)現(xiàn)了 count。
重點(diǎn)來了,內(nèi)存在這里是怎么管理的?盡管 makeCounter() 調(diào)用結(jié)束了,它的 Lexical Environment 依然保存在內(nèi)存中,這是因?yàn)榍短缀瘮?shù)的 [[Environment]] 引用了它。
通常,Lexical Environment 對(duì)象隨著使用它的函數(shù)的存在而存在。沒有函數(shù)引用它的時(shí)候,它才會(huì)被清除。
counter() 函數(shù)不只是返回 count,還會(huì)對(duì)其 +1 操作。這個(gè)修改已經(jīng)在“適當(dāng)?shù)奈恢谩蓖瓿闪恕?b>count 的值在它的當(dāng)前環(huán)境中被修改。
這一步再次調(diào)用 count,原理完全相同。
(譯者:總結(jié)一下,聲明時(shí)記錄環(huán)境 [[Environment]](函數(shù)所在環(huán)境),執(zhí)行時(shí)創(chuàng)建詞法環(huán)境(局部+ outer 就是引用 [[Environment]]),而閉包就是函數(shù) + 它的詞法環(huán)境,所以定義上來說所有函數(shù)都是閉包,但是之后被返回出來可以使用的閉包才是“實(shí)用意義”上的閉包)
下一個(gè) counter() 調(diào)用操作同上。
本章開頭第二個(gè)問題的答案現(xiàn)在顯而易見了。
以下代碼的 work() 函數(shù)通過外層 lexical environment 引用了它原地點(diǎn)的 name :
所以這里的答案是 "Pete"。
但是如果 makeWorker() 沒了 let name ,如我們所見,作用域搜索會(huì)到達(dá)外層,獲取全局變量。這個(gè)情況下答案會(huì)是 "John" 。
閉包(Closure)代碼塊、循環(huán)、 IIFE
開發(fā)者們都應(yīng)該知道編程領(lǐng)域的通用名詞閉包(closure)。
閉包是一個(gè)記錄并可訪問外層變量的函數(shù)。在一些編程語言中是不存在的,或者要以一種特殊的方式書寫以實(shí)現(xiàn)這個(gè)功能。但是如上面解釋的,JavaScript 的所有函數(shù)都個(gè)閉包。
這就是閉包:它們使用 [[Environment]] 屬性自動(dòng)記錄各自的創(chuàng)建地點(diǎn),然后由此訪問外部變量。
在前端面試中,如果面試官問你什么是閉包,正確答案應(yīng)該包括閉包的定義,以及解釋為何 JavaScript 的所有函數(shù)都是閉包,最好可以再簡單說說里面的技術(shù)細(xì)節(jié):[[Environment]] 屬性和 Lexical Environments 的原理。
上面的例子都著重于函數(shù),但是 Lexical Environment 也存在于代碼塊 {...} 。
它們在代碼塊運(yùn)行時(shí)創(chuàng)建,包含塊局部變量。這里有一些例子。
If下例中,當(dāng)執(zhí)行到 if 塊,會(huì)為這個(gè)塊創(chuàng)建新的 "if-only" Lexical Environment :
與函數(shù)同樣原理,塊內(nèi)可以找到 phrase,但是塊外不能使用塊內(nèi)的變量和函數(shù)。如果執(zhí)意在 if 外面用 user,那只能得到一個(gè)報(bào)錯(cuò)了。
For, while對(duì)于循環(huán),每一次迭代都會(huì)有自己的 Lexical Environment,在 for 里定義的變量,也是塊的局部變量,也屬于塊的 Lexical Environment :
for (let i = 0; i < 10; i++) { // Each loop has its own Lexical Environment // {i: value} } alert(i); // Error, no such variable
let i 只在塊內(nèi)可用,每次循環(huán)都有它自己的 Lexical Environment,每次循環(huán)都會(huì)帶著當(dāng)前的 i,最后循環(huán)結(jié)束,i 不可用。
代碼塊我們也可以直接用 {…} 把變量隔離到一個(gè)“局部作用域”(local scope)。
在瀏覽器中所有 script 共享全局變量,這就很容易造成變量的重名、覆蓋。
為了避免這種情況我們可以使用代碼塊隔離自己的代碼:
{ // do some job with local variables that should not be seen outside let message = "Hello"; alert(message); // Hello } alert(message); // Error: message is not defined
代碼塊有自己的 Lexical Environment ,塊外無法訪問塊內(nèi)變量。
IIFE以前沒有代碼塊,要實(shí)現(xiàn)上述效果要依靠所謂的“立即執(zhí)行函數(shù)表達(dá)式”(immediately-invoked function expressions ,縮寫 IIFE):
(function() { let message = "Hello"; alert(message); // Hello })();
這個(gè)函數(shù)表達(dá)式創(chuàng)建后立即執(zhí)行,代碼立即執(zhí)行并有自己的私有變量。
函數(shù)表達(dá)式需要被括號(hào)包裹。JavaScript 執(zhí)行時(shí)遇到 "function" 會(huì)理解為一個(gè)函數(shù)聲明,函數(shù)聲明必須有名稱,沒有就會(huì)報(bào)錯(cuò):
// Error: Unexpected token ( function() { // <-- JavaScript cannot find function name, meets ( and gives error let message = "Hello"; alert(message); // Hello }();
你可能會(huì)說:“那我給他加個(gè)名字咯”,但這依然行不通,JavaScript 不允許函數(shù)聲明立刻被執(zhí)行:
// syntax error because of brackets below function go() { }(); // <-- can"t call Function Declaration immediately
圓括號(hào)告訴 JavaScript 這個(gè)函數(shù)創(chuàng)建于其他表達(dá)式的上下文,因此這是個(gè)函數(shù)表達(dá)式。不需要名稱,也可以立即執(zhí)行。
也有其他方法告訴 JavaScript 我們需要的是函數(shù)表達(dá)式:
// 創(chuàng)建 IIFE 的方法 (function() { alert("Brackets around the function"); })(); (function() { alert("Brackets around the whole thing"); }()); !function() { alert("Bitwise NOT operator starts the expression"); }(); +function() { alert("Unary plus starts the expression"); }();垃圾回收
Lexical Environment 對(duì)象與普通的值的內(nèi)存管理規(guī)則是一樣的。
通常 Lexical Environment 在函數(shù)運(yùn)行完畢就會(huì)被清理:
function f() { let value1 = 123; let value2 = 456; } f();
這兩個(gè)值是 Lexical Environment 的屬性,但是 f() 執(zhí)行完后,這個(gè) Lexical Environment 無任何變量引用(unreachable),所以它會(huì)從內(nèi)存刪除。
...但是如果有內(nèi)嵌函數(shù),它的 [[Environment]] 會(huì)引用 f 的 Lexical Environment(reachable):
function f() { let value = 123; function g() { alert(value); } return g; } let g = f(); // g is reachable, and keeps the outer lexical environment in memory
注意,f() 如果被多次調(diào)用,返回的函數(shù)都被保存,相應(yīng)的 Lexical Environment 會(huì)分別保存在內(nèi)存:
function f() { let value = Math.random(); return function() { alert(value); }; } // 3 functions in array, every one of them links to Lexical Environment // from the corresponding f() run // LE LE LE let arr = [f(), f(), f()];
Lexical Environment 對(duì)象在不可觸及(unreachable)后被清除:無嵌套函數(shù)引用它。下例中, g 自身不被引用后, value 也會(huì)被清除:
function f() { let value = 123; function g() { alert(value); } return g; } let g = f(); // while g is alive // there corresponding Lexical Environment lives g = null; // ...and now the memory is cleaned up實(shí)踐中的優(yōu)化
理論上,函數(shù)還在,它的所有外部變量都會(huì)被保留。
但在實(shí)踐中,JavaScript 引擎可能會(huì)對(duì)此作出優(yōu)化,引擎在分析變量的使用情況后,把沒有使用的外部變量刪除。
在 V8 (Chrome, Opera)有個(gè)問題,這些被刪除的變量不能在 debugger 觀察了。
嘗試在 Chrome Developer Tools 運(yùn)行以下代碼:
function f() { let value = Math.random(); function g() { debugger; // 在 console 輸入 alert( value ); 發(fā)現(xiàn)無此變量! } return g; } let g = f(); g();
你可以看到,這里沒有保存 value 變量!理論上它應(yīng)該是可訪問的,但是引擎優(yōu)化移除了這個(gè)變量。
還有一個(gè)有趣的 debug 問題。下面的代碼 alert 出外面的同名變量而不是里面的:
let value = "Surprise!"; function f() { let value = "the closest value"; function g() { debugger; // in console: type alert( value ); Surprise! } return g; } let g = f(); g();
再會(huì)!
如果你用 Chrome/Opera 來debug ,很快就能發(fā)現(xiàn)這個(gè) V8 feature。
這不是 bug 而是 V8 feature,或許將來會(huì)被修改。至于改沒改,運(yùn)行一下上面的例子就能判斷啦。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/107967.html
摘要:插件開發(fā)前端掘金作者原文地址譯者插件是為應(yīng)用添加全局功能的一種強(qiáng)大而且簡單的方式。提供了與使用掌控異步前端掘金教你使用在行代碼內(nèi)優(yōu)雅的實(shí)現(xiàn)文件分片斷點(diǎn)續(xù)傳。 Vue.js 插件開發(fā) - 前端 - 掘金作者:Joshua Bemenderfer原文地址: creating-custom-plugins譯者:jeneser Vue.js插件是為應(yīng)用添加全局功能的一種強(qiáng)大而且簡單的方式。插....
摘要:然而學(xué)習(xí)布局,你只要學(xué)習(xí)幾個(gè)手機(jī)端頁面自適應(yīng)解決方案布局進(jìn)階版附源碼示例前端掘金一年前筆者寫了一篇手機(jī)端頁面自適應(yīng)解決方案布局,意外受到很多朋友的關(guān)注和喜歡。 十分鐘學(xué)會(huì) Fiddler - 后端 - 掘金一.Fiddler介紹 Fiddler是一個(gè)http抓包改包工具,fiddle英文中有欺騙、偽造之意,與wireshark相比它更輕量級(jí),上手簡單,因?yàn)橹荒茏ttp和https數(shù)據(jù)...
摘要:最近看前端都展開了幾場而我大知乎最熱語言還沒有相關(guān)。有關(guān)書籍的介紹,大部分截取自是官方介紹。但從開始,標(biāo)準(zhǔn)庫為我們提供了模塊,它提供了和兩個(gè)類,實(shí)現(xiàn)了對(duì)和的進(jìn)一步抽象,對(duì)編寫線程池進(jìn)程池提供了直接的支持。 《流暢的python》閱讀筆記 《流暢的python》是一本適合python進(jìn)階的書, 里面介紹的基本都是高級(jí)的python用法. 對(duì)于初學(xué)python的人來說, 基礎(chǔ)大概也就夠用了...
摘要:函數(shù)式編程前端掘金引言面向?qū)ο缶幊桃恢币詠矶际侵械闹鲗?dǎo)范式。函數(shù)式編程是一種強(qiáng)調(diào)減少對(duì)程序外部狀態(tài)產(chǎn)生改變的方式。 JavaScript 函數(shù)式編程 - 前端 - 掘金引言 面向?qū)ο缶幊桃恢币詠矶际荍avaScript中的主導(dǎo)范式。JavaScript作為一門多范式編程語言,然而,近幾年,函數(shù)式編程越來越多得受到開發(fā)者的青睞。函數(shù)式編程是一種強(qiáng)調(diào)減少對(duì)程序外部狀態(tài)產(chǎn)生改變的方式。因此,...
摘要:使用上一篇文章的例子來說明下自由變量進(jìn)階期深入淺出圖解作用域鏈和閉包訪問外部的今天是今天是其中既不是參數(shù),也不是局部變量,所以是自由變量。 (關(guān)注福利,關(guān)注本公眾號(hào)回復(fù)[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實(shí)戰(zhàn)、面試指導(dǎo)) 本周正式開始前端進(jìn)階的第二期,本周的主題是作用域閉包,今天是第7天。 本計(jì)劃一共28期,每期重點(diǎn)攻克一個(gè)面試重難點(diǎn),如果你還不了解本進(jìn)階計(jì)...
閱讀 1844·2021-11-23 09:51
閱讀 1303·2021-11-18 10:02
閱讀 973·2021-10-25 09:44
閱讀 2113·2019-08-26 18:36
閱讀 1633·2019-08-26 12:17
閱讀 1158·2019-08-26 11:59
閱讀 2755·2019-08-23 15:56
閱讀 3367·2019-08-23 15:05