摘要:作用域和閉包是最重要的概念之一,想要進一步學習,就必須理解作用域和閉包的工作原理。全局和局部作用域的關系在函數(shù)體內,局部變量的優(yōu)先級高于同名的全局變量。作用域鏈的用途,是保證對執(zhí)行環(huán)境有權訪問的所有變量和函數(shù)的有序訪問。
作用域和閉包是 JavaScript 最重要的概念之一,想要進一步學習 JavaScript,就必須理解 JavaScript 作用域和閉包的工作原理。
作用域任何程序設計語言都有作用域的概念,簡單的說,作用域就是變量與函數(shù)的可訪問范圍,即作用域控制著變量與函數(shù)的可見性和生命周期。在 JavaScript 中,變量的作用域有全局作用域和局部作用域兩種。
全局作用域(Global Scope)在代碼中任何地方都能訪問到的對象擁有全局作用域,一般來說以下三種情形擁有全局作用域:
1.最外層函數(shù)和在最外層函數(shù)外面定義的變量擁有全局作用域,例如:
var global = "global"; // 顯式聲明一個全局變量 function checkscope() { var local = "local"; // 顯式聲明一個局部變量 return global; // 返回全局變量的值 } console.log(global); // "global" console.log(checkscope()); // "global" console.log(local); // error: local is not defined.
上面代碼中,global 是全局變量,不管是在 checkscope() 函數(shù)內部還是外部,都能訪問到全局變量 global。
2.所有末定義直接賦值的變量自動聲明為擁有全局作用域,例如:
function checkscope() { var local = "local"; // 顯式聲明一個局部變量 global = "global"; // 隱式聲明一個全局變量(不好的寫法) } console.log(global); // "global" console.log(local); // error: local is not defined.
上面代碼中,變量 global 未用 var 關鍵字定義就直接賦值,所以隱式的創(chuàng)建了全局變量 global,但這種寫法容易造成誤解,應盡量避免這種寫法。
3.所有 window 對象的屬性擁有全局作用域
一般情況下,window 對象的內置屬性都擁有全局作用域,例如 window.name、window.location、window.top 等等。
局部作用域(Local Scope)和全局作用域相反,局部作用域一般只在固定的代碼片段內可訪問到。最常見的是在函數(shù)體內定義的變量,只能在函數(shù)體內使用。例如:
function checkscope() { var local = "local"; // 顯式聲明一個局部變量 return local; // 返回全局變量的值 } console.log(checkscope()); // "local" console.log(local); // error: local is not defined.
上面代碼中,在函數(shù)體內定義了變量 local,在函數(shù)體內是可以訪問了,在函數(shù)外訪問就報錯了。
全局和局部作用域的關系在函數(shù)體內,局部變量的優(yōu)先級高于同名的全局變量。如果在函數(shù)內聲明的一個局部變量或者函數(shù)參數(shù)中帶有的變量和全局變量重名,那么全局變量就被局部變量所遮蓋。
var scope = "global"; // 聲明一個全局變量 function checkscope() { var scope = "local"; // 聲明一個同名的局部變量 return scope; // 返回局部變量的值,而不是全局變量的值 } console.log(checkscope()); // "local"
盡管在全局作用域編寫代碼時可以不寫 var 語句,但聲明局部變量時則必須使用 var 語句。思考一下如果不這樣做會怎樣:
scope = "global"; // 聲明一個全局變量,甚至不用 var 來聲明 function checkscope2() { scope = "local"; // 糟糕!我們剛修改了全局變量 myscope = "local"; // 這里顯式地聲明了一個新的全局變量 return [scope, myscope];// 返回兩個值 } console.log(checkscope2()); // ["local", "local"],產生了副作用 console.log(scope); // "local",全局變量修改了 console.log(myscope); // "local",全局命名空間搞亂了
函數(shù)定義是可以嵌套的。由于每個函數(shù)都有它自己的作用域,因此會出現(xiàn)幾個局部作用域嵌套的情況,例如:
var scope = "global scope"; // 全局變量 function checkscope() { var scope = "local scope"; //局部變量 function nested() { var scope = "nested scope"; // 嵌套作用域內的局部變量 return scope; // 返回當前作用域內的值 } return nested(); } console.log(checkscope()); // "nested scope"函數(shù)作用域和聲明提前
在一些類似 C 語言的編程語言中,花括號內的每一段代碼都具有各自的作用域,而且變量在聲明它們的代碼段之外是不可見的,我們稱為塊級作用域(block scope),而 JavaScript 中沒有塊級作用域。JavaScript 取而代之地使用了函數(shù)作用域(function scope),變量在聲明它們的函數(shù)體以及這個函數(shù)體嵌套的任意函數(shù)體內都是有定義的。
在如下所示的代碼中,在不同位置定義了變量 i、j 和 k,它們都在同一個作用域內,這三個變量在函數(shù)體內均是有定義的。
function test(o) { var i = 0; // i在整個函數(shù)體內均是有定義的 if (typeof o == "object") { var j = 0; // j在函數(shù)體內是有定義的,不僅僅是在這個代碼段內 for (var k = 0; k < 10; k++) { // k在函數(shù)體內是有定義的,不僅僅是在循環(huán)內 console.log(k); // 輸出數(shù)字0~9 } console.log(k); // k已經定義了,輸出10 } console.log(j); // j已經定義了,但可能沒有初始化 }
JavaScript 的函數(shù)作用域是指在函數(shù)內聲明的所有變量在函數(shù)體內始終是可見的。有意思的是,這意味著變量在聲明之前甚至已經可用。JavaScript 的這個特性被非正式地稱為聲明提前(hoisting),即 JavaScript 函數(shù)里聲明的所有變量(但不涉及賦值)都被「提前」至函數(shù)體的頂部,看一下如下代碼:
var scope = "global"; function f() { console.log(scope); // 輸出"undefined",而不是"global" var scope = "local"; // 變量在這里賦初始值,但變量本身在函數(shù)體內任何地方均是有定義的 console.log(scope); // 輸出"local" }
你可能會誤以為函數(shù)中的第一行會輸出 "global",因為代碼還沒有執(zhí)行到 var 語句聲明局部變量的地方。其實不然,由于函數(shù)作用域的特性,局部變量在整個函數(shù)體始終是有定義的,也就是說,在函數(shù)體內局部變量遮蓋了同名全局變量。盡管如此,只有在程序執(zhí)行到 var 語句的時候,局部變量才會被真正賦值。因此,上述過程等價于:將函數(shù)內的變量聲明“提前”至函數(shù)體頂部,同時變量初始化留在原來的位置:
function f() { var scope; // 在函數(shù)頂部聲明了局部變量 console.log(scope); // 變量存在,但其值是"undefined" scope = "local"; // 這里將其初始化并賦值 console.log(scope); // 這里它具有了我們所期望的值 }
在具有塊級作用域的編程語言中,在狹小的作用域里讓變量聲明和使用變量的代碼盡可能靠近彼此,通常來講,這是一個非常不錯的編程習慣。由于 JavaScript 沒有塊級作用域,因此一些程序員特意將變量聲明放在函數(shù)體頂部,而不是將聲明靠近放在使用變量之處。這種做法使得他們的源代碼非常清晰地反映了真實的變量作用域。
作用域鏈當代碼在一個環(huán)境中執(zhí)行時,會創(chuàng)建變量對象的一個作用域鏈(scope chain)。作用域鏈的用途,是保證對執(zhí)行環(huán)境有權訪問的所有變量和函數(shù)的有序訪問。作用域鏈的前端,始終都是當前執(zhí)行的代碼所在環(huán)境的變量對象。如果這個環(huán)境是函數(shù),則將其活動對象(activation object)作為變量對象?;顒訉ο笤谧铋_始時只包含一個變量,即 arguments 對象(這個對象在全局環(huán)境中是不存在的)。作用域鏈中的下一個變量對象來自包含(外部)環(huán)境,而再下一個變量對象則來自下一個包含環(huán)境。這樣,一直延續(xù)到全局執(zhí)行環(huán)境;全局執(zhí)行環(huán)境的變量對象始終都是作用域鏈中的最后一個對象。
標識符解析是沿著作用域鏈一級一級地搜索標識符的過程。搜索過程始終從作用域鏈的前端開始,然后逐級地向后回溯,直至找到標識符為止(如果找不到標識符,通常會導致錯誤發(fā)生)。
請看下面的示例代碼:
var color = "blue"; function changeColor(){ if (color === "blue"){ color = "red"; } else { color = "blue"; } } console.log(changeColor());
在這個簡單的例子中,函數(shù) changeColor() 的作用域鏈包含兩個對象:它自己的變量對象(其中定義著 arguments 對象)和全局環(huán)境的變量對象??梢栽诤瘮?shù)內部訪問變量 color,就是因為可以在這個作用域鏈中找到它。
此外,在局部作用域中定義的變量可以在局部環(huán)境中與全局變量互換使用,如下面這個例子所示:
var color = "blue"; function changeColor(){ var anotherColor = "red"; function swapColors(){ var tempColor = anotherColor; anotherColor = color; color = tempColor; // 這里可以訪問color、anotherColor和tempColor } // 這里可以訪問color和anotherColor,但不能訪問tempColor swapColors(); } // 這里只能訪問color changeColor();
以上代碼共涉及3個執(zhí)行環(huán)境:全局環(huán)境、changeColor() 的局部環(huán)境和 swapColors() 的局部環(huán)境。全局環(huán)境中有一個變量 color 和一個函數(shù) changeColor()。changeColor() 的局部環(huán)境中有一個名為 anotherColor 的變量和一個名為 swapColors() 的函數(shù),但它也可以訪問全局環(huán)境中的變量 color。swapColors() 的局部環(huán)境中有一個變量 tempColor,該變量只能在這個環(huán)境中訪問到。無論全局環(huán)境還是 changeColor() 的局部環(huán)境都無權訪問 tempColor。然而,在 swapColors() 內部則可以訪問其他兩個環(huán)境中的所有變量,因為那兩個環(huán)境是它的父執(zhí)行環(huán)境。下圖形象地展示了前面這個例子的作用域鏈。
上圖中的矩形表示特定的執(zhí)行環(huán)境。其中,內部環(huán)境可以通過作用域鏈訪問所有的外部環(huán)境,但外部環(huán)境不能訪問內部環(huán)境中的任何變量和函數(shù)。這些環(huán)境之間的聯(lián)系是線性、有次序的。每個環(huán)境都可以向上搜索作用域鏈,以查詢變量和函數(shù)名;但任何環(huán)境都不能通過向下搜索作用域鏈而進入另一個執(zhí)行環(huán)境。對于這個例子中的 swapColors() 而言,其作用域鏈中包含3個對象:swapColors() 的變量對象、changeColor() 的變量對象和全局變量對象。swapColors() 的局部環(huán)境開始時會先在自己的變量對象中搜索變量和函數(shù)名,如果搜索不到則再搜索上一級作用域鏈。changeColor() 的作用域鏈中只包含兩個對象:它自己的變量對象和全局變量對象。這也就是說,它不能訪問 swapColors() 的環(huán)境。函數(shù)參數(shù)也被當作變量來對待,因此其訪問規(guī)則與執(zhí)行環(huán)境中的其他變量相同。
閉包MDN 對閉包的定義:
閉包是指那些能夠訪問獨立(自由)變量的函數(shù)(變量在本地使用,但定義在一個封閉的作用域中)。換句話說,這些函數(shù)可以「記憶」它被創(chuàng)建時候的環(huán)境。
《JavaScript 權威指南(第6版)》對閉包的定義:
函數(shù)對象可以通過作用域鏈相互關聯(lián)起來,函數(shù)體內部的變量都可以保存在函數(shù)作用域內,這種特性在計算機科學文獻中稱為閉包。
《JavaScript 高級程序設計(第3版)》對閉包的定義:
閉包是指有權訪問另一個函數(shù)作用域中的變量的函數(shù)。
上面這些定義都比較晦澀難懂,阮一峰的解釋稍微好理解一些:
閉包的用途由于在 Javascript 語言中,只有函數(shù)內部的子函數(shù)才能讀取局部變量,因此可以把閉包簡單理解成定義在一個函數(shù)內部的函數(shù)。
閉包可以用在許多地方。它的最大用處有兩個,一個是可以讀取函數(shù)內部的變量(作用域鏈),另一個就是讓這些變量的值始終保持在內存中。怎么來理解這句話呢?請看下面的代碼。
function fun() { var n = 1; add = function() { n += 1 } function fun2(){ console.log(n); } return fun2; } var result = fun(); result(); // 1 add(); result(); // 2
在這段代碼中,result 實際上就是函數(shù) fun2。它一共運行了兩次,第一次的值是 1,第二次的值是 2。這證明了,函數(shù) fun 中的局部變量 n 一直保存在內存中,并沒有在 fun 調用后被自動清除。
為什么會這樣呢?原因就在于 fun 是 fun2 的父函數(shù),而 fun2 被賦給了一個全局變量,這導致 fun2 始終在內存中,而 fun2 的存在依賴于 fun,因此 fun 也始終在內存中,不會在調用結束后,被垃圾回收機制(garbage collection)回收。
這段代碼中另一個值得注意的地方,就是 add = function() { n += 1 } 這一行。首先,變量 add 前面沒有使用 var 關鍵字,因此 add 是一個全局變量,而不是局部變量。其次,add 的值是一個匿名函數(shù)(anonymous function),而這個匿名函數(shù)本身也是一個閉包,和 fun2 處于同一作用域,所以 add 相當于是一個 setter,可以在函數(shù)外部對函數(shù)內部的局部變量進行操作。
計數(shù)器的困境我們再來看一個經典例子「計數(shù)器的困境」,假設你想統(tǒng)計一些數(shù)值,且該計數(shù)器在所有函數(shù)中都是可用的。你可以定義一個全局變量 counter 當做計數(shù)器,再定義一個 add() 函數(shù)來設置計數(shù)器遞增。代碼如下:
var counter = 0; function add() { return counter += 1; } console.log(add()); console.log(add()); console.log(add()); // 計數(shù)器現(xiàn)在為 3
計數(shù)器數(shù)值在執(zhí)行 add() 函數(shù)時發(fā)生變化。但問題來了,頁面上的任何腳本都能改變計數(shù)器 counter,即便沒有調用 add() 函數(shù)。如果我們將計數(shù)器 counter 定義在 add() 函數(shù)內部,就不會被外部腳本隨意修改到計數(shù)器的值了。代碼如下:
function add() { var counter = 0; return counter += 1; } console.log(add()); console.log(add()); console.log(add()); // 本意是想輸出 3, 但事與愿違,輸出的都是 1
因為每次調用 add() 函數(shù),計數(shù)器都會被重置為 0,輸出的都是 1,這并不是我們想要的結果。閉包正好可以解決這個問題,我們在 add() 函數(shù)內部,再定義一個 plus() 內嵌函數(shù)(閉包),內嵌函數(shù) plus() 可以訪問父函數(shù)的 counter 變量。代碼如下:
function add() { var counter = 0; var plus = function() {counter += 1;} plus(); return counter; }
接下來,只要我們能在外部訪問 plus() 函數(shù),并且確保 counter = 0 只執(zhí)行一次,就能解決計數(shù)器的困境。代碼如下:
var add = function() { var counter = 0; var plus = function() {return counter += 1;} return plus; } var puls2 = add(); console.log(puls2()); console.log(puls2()); console.log(puls2()); // 計數(shù)器為 3
計數(shù)器 counter 受 add() 函數(shù)的作用域保護,只能通過 puls2 方法修改。
使用閉包的注意點由于閉包會使得函數(shù)中的變量都被保存在內存中,內存消耗很大,所以不能濫用閉包,否則會造成網頁的性能問題,在 IE 中可能導致內存泄露。解決方法是,在退出函數(shù)之前,將不使用的局部變量全部刪除或設置為 null,斷開變量和內存的聯(lián)系。
閉包會在父函數(shù)外部,改變父函數(shù)內部變量的值。所以,如果你把父函數(shù)當作對象(object)使用,把閉包當作它的公用方法(public method),把內部變量當作它的私有屬性(private value),這時一定要小心,不要隨便改變父函數(shù)內部變量的值。
JavaScript 閉包是一種強大的語言特性。通過使用這個語言特性來隱藏變量,可以避免覆蓋其他地方使用的同名變量,理解閉包有助于編寫出更有效也更簡潔的代碼。
this 關鍵字談到作用域和閉包就不得不說 this 關鍵字,雖然它們之間關聯(lián)不大,但是它們一起使用卻容易讓人產生疑惑。下面列出了使用 this 的大部分場景,帶大家一探究竟。
this 是 JavaScript 的關鍵字,指函數(shù)執(zhí)行時的上下文,跟函數(shù)定義時的上下文無關。隨著函數(shù)使用場合的不同,this 的值會發(fā)生變化。但是有一個總的原則,那就是 this 指代的是調用函數(shù)的那個對象。
全局上下文在全局上下文中,也就是在任何函數(shù)體外部,this 指代全局對象。
// 在瀏覽器中,this 指代全局對象 window console.log(this === window); // true函數(shù)上下文
在函數(shù)上下文中,也就是在任何函數(shù)體內部,this 指代調用函數(shù)的那個對象。
函數(shù)調用中的 thisfunction f1(){ return this; } console.log(f1() === window); // true
如上代碼所示,直接定義一個函數(shù) f1(),相當于為 window 對象定義了一個屬性。直接執(zhí)行函數(shù) f1(),相當于執(zhí)行 window.f1()。所以函數(shù) f1() 中的 this 指代調用函數(shù)的那個對象,也就是 window 對象。
function f2(){ "use strict"; // 這里是嚴格模式 return this; } console.log(f2() === undefined); // true
如上代碼所示,在「嚴格模式」下,禁止 this 關鍵字指向全局對象(在瀏覽器環(huán)境中也就是 window 對象),this 的值將維持 undefined 狀態(tài)。
對象方法中的 thisvar o = { name: "stone", f: function() { return this.name; } }; console.log(o.f()); // "stone"
如上代碼所示,對象 o 中包含一個屬性 name 和一個方法 f()。當我們執(zhí)行 o.f() 時,方法 f() 中的 this 指代調用函數(shù)的那個對象,也就是對象 o,所以 this.name 也就是 o.name。
注意,在何處定義函數(shù)完全不會影響到 this 的行為,我們也可以首先定義函數(shù),然后再將其附屬到 o.f。這樣做 this 的行為也一致。如下代碼所示:
var fun = function() { return this.name; }; var o = { name: "stone" }; o.f = fun; console.log(o.f()); // "stone"
類似的,this 的綁定只受最靠近的成員引用的影響。在下面的這個例子中,我們把一個方法 g() 當作對象 o.b 的函數(shù)調用。在這次執(zhí)行期間,函數(shù)中的 this 將指向 o.b。事實上,這與對象本身的成員沒有多大關系,最靠近的引用才是最重要的。
o.b = { name: "sophie" g: fun, }; console.log(o.b.g()); // "sophie"eval() 方法中的 this
eval() 方法可以將字符串轉換為 JavaScript 代碼,使用 eval() 方法時,this 指向哪里呢?答案很簡單,看誰在調用 eval() 方法,調用者的執(zhí)行環(huán)境中的 this 就被 eval() 方法繼承下來了。如下代碼所示:
// 全局上下文 function f1(){ return eval("this"); } console.log(f1() === window); // true // 函數(shù)上下文 var o = { name: "stone", f: function() { return eval("this.name"); } }; console.log(o.f()); // "stone"call() 和 apply() 方法中的 this
call() 和 apply() 是函數(shù)對象的方法,它的作用是改變函數(shù)的調用對象,它的第一個參數(shù)就表示改變后的調用這個函數(shù)的對象。因此,this 指代的就是這兩個方法的第一個參數(shù)。
var x = 0; function f() { console.log(this.x); } var o = {}; o.x = 1; o.m = f; o.m.apply(); // 0
call() 和 apply() 的參數(shù)為空時,默認調用全局對象。因此,這時的運行結果為 0,證明 this 指的是全局對象。如果把最后一行代碼修改為:
o.m.apply(o); // 1
運行結果就變成了 1,證明了這時 this 指代的是對象 o。
bind() 方法中的 thisECMAScript 5 引入了 Function.prototype.bind。調用 f.bind(someObject) 會創(chuàng)建一個與 f 具有相同函數(shù)體和作用域的函數(shù),但是在這個新函數(shù)中,this 將永久地被綁定到了 bind 的第一個參數(shù),無論這個函數(shù)是如何被調用的。如下代碼所示:
function f() { return this.a; } var g = f.bind({ a: "stone" }); console.log(g()); // stone var o = { a: 28, f: f, g: g }; console.log(o.f(), o.g()); // 28, stoneDOM 事件處理函數(shù)中的 this
一般來講,當函數(shù)使用 addEventListener,被用作事件處理函數(shù)時,它的 this 指向觸發(fā)事件的元素。如下代碼所示:
test
但在 IE 瀏覽器中,當函數(shù)使用 attachEvent ,被用作事件處理函數(shù)時,它的 this 卻指向 window。如下代碼所示:
內聯(lián)事件處理函數(shù)中的 thistest
當代碼被內聯(lián)處理函數(shù)調用時,它的 this 指向監(jiān)聽器所在的 DOM 元素。如下代碼所示:
上面的 alert 會顯示 button,注意只有外層代碼中的 this 是這樣設置的。如果 this 被包含在匿名函數(shù)中,則又是另外一種情況了。如下代碼所示:
在這種情況下,this 被包含在匿名函數(shù)中,相當于處于全局上下文中,所以它指向 window 對象。
關卡仔細想想,下面代碼塊會輸出什么結果呢?
// 挑戰(zhàn)一 function func1() { function func2() { console.log(this) } return func2; } func1()(); // ???
// 挑戰(zhàn)二 scope = "stone"; function Func() { var scope = "sophie"; function inner() { console.log(scope); } return inner; } var ret = Func(); ret(); // ???
// 挑戰(zhàn)三 scope = "stone"; function Func() { var scope = "sophie"; function inner() { console.log(scope); } scope = "tommy"; return inner; } var ret = Func(); ret(); // ???
// 挑戰(zhàn)四 scope = "stone"; function Bar() { console.log(scope); } function Func() { var scope = "sophie"; return Bar; } var ret = Func(); ret(); // ???
// 挑戰(zhàn)五 var name = "The Window"; var object = { name: "My Object", getNameFunc: function() { return function() { return this.name; }; } }; console.log(object.getNameFunc()()); // ???
// 挑戰(zhàn)六 var name = "The Window"; var object = { name: "My Object", getNameFunc: function() { var that = this; return function() { return that.name; }; } }; console.log(object.getNameFunc()()); // ???更多
關注微信公眾號「劼哥舍」回復「答案」,獲取關卡詳解。
關注 https://github.com/stone0090/javascript-lessons,獲取最新動態(tài)。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://systransis.cn/yun/91340.html
摘要:對象數(shù)組初始化表達式,闖關記之上文檔對象模型是針對和文檔的一個。闖關記之數(shù)組數(shù)組是值的有序集合。數(shù)組是動態(tài)的,根闖關記之語法的語法大量借鑒了及其他類語言如和的語法。 《JavaScript 闖關記》之 DOM(下) Element 類型 除了 Document 類型之外,Element 類型就要算是 Web 編程中最常用的類型了。Element 類型用于表現(xiàn) XML 或 HTML 元素...
摘要:本課程之所以叫做闖關記,是因為部分章節(jié)精心設計了挑戰(zhàn)關卡,通過提供更多的實戰(zhàn)機會,讓大家可以循序漸進地有目的地有挑戰(zhàn)地開展學習。課程結構及目錄以下目錄只是初步構想,課程結構及內容會根據(jù)實際情況隨時進行調整。 為何寫作此課程 stone 主要負責基于 Web 的企業(yè)內部管理系統(tǒng)的開發(fā),雖然能夠熟練地使用 JavaScript,但隨著對 JavaScript 的理解越來越深,才發(fā)現(xiàn)自己尚...
摘要:前言上篇闖關模式作用域鏈和閉包上任務三全局作用域和變量遮蔽全局作用域理解作用域鏈在哪結束很重要所有的運行時環(huán)境都必須隱式創(chuàng)建一個全局作用域對象瀏覽器中是,中是,這個對象就位于作用域鏈的頂端在任務一中,我們忽略了一個細節(jié),即當不使用或者等定義 前言 上篇:【闖關模式】作用域、鏈和閉包 上 任務三 Global Scope & Shadowing 全局作用域和變量遮蔽 全局作用域(Glob...
摘要:內存回收此時,局部變量就沒有存在的必要了,因此可以釋放它們的內存以供將來使用。局部變量會在它們離開執(zhí)行環(huán)境時自動被解除引用,如下面這個例子所示手工解除的引用由于局部變量在函數(shù)執(zhí)行完畢后就離開了其執(zhí)行環(huán)境,因此無需我們顯式地去為它解除引用。 JavaScript 具有自動垃圾收集機制(GC:Garbage Collecation),也就是說,執(zhí)行環(huán)境會負責管理代碼執(zhí)行過程中使用的內存。而...
摘要:前言這個系列是翻譯自中的直接闖關作用域鏈和閉包作用域,作用域鏈,閉包和垃圾回收機制都有一個共同點學了就忘閉包到底是干啥的啥時候發(fā)生垃圾回收機制作用域鏈到底是啥這個教程讓你發(fā)現(xiàn)這些都是小意思。 前言 這個系列是翻譯自 nodeschool.io中的 scope-chains-closures 直接闖關: npm install -g scope-chains-closures scope...
閱讀 1656·2021-09-22 15:21
閱讀 2874·2021-09-09 09:32
閱讀 2705·2021-09-02 09:52
閱讀 3317·2019-08-30 14:02
閱讀 2232·2019-08-26 13:25
閱讀 1464·2019-08-26 13:24
閱讀 1613·2019-08-26 10:31
閱讀 1566·2019-08-26 10:16