滿滿的乾貨,面試必bei系列,參考大量資料,並集合本身的理解以及相關的面試題,對JS核心知識點中的做用域、閉包、this、上下文進行了梳理。因爲篇幅有限,這裏只對我認爲最重要的知識作了介紹,一些常識性的東西你們能夠參考高程。javascript
又叫執行環境,環境。java
執行環境定義了變量或者環境有權訪問的其餘數據,據定了它們的各自行爲 --高程
一個函數執行的時候,會產生一個屬於本身的執行環境。環境裏面有一個變量對象variable object(VO),OA裏面存放着環境中定義的全部變量和函數,做用域鏈(scope chain),this。
函數執行,環境產生被推入環境棧,函數執行完,環境出棧並被銷燬(閉包例外),把控制權返回給以前的執行環境。面試
js中的做用域是靜態做用域,靜態做用域又叫作詞法做用域,採用詞法做用域的變量叫詞法變量。詞法變量有一個在編譯時靜態肯定的做用域。詞法變量的做用域能夠是一個函數或一段代碼,該變量在這段代碼區域內可見(visibility);在這段區域之外該變量不可見(或沒法訪問)。詞法做用域裏,取變量的值時,會檢查函數定義時的文本環境,捕捉函數定義時對該變量的綁定。--wiki
做用域是一套規則
,用於肯定在何處以及如何查找變量(標識符)。--你不知道的javascript
做用域就是執行的時候,給環境變量賦值的一種規則,這種規則在函數定義的時候就已經肯定了,和運行無關
。
js只有全局做用域和函數做用域,沒有塊做用域。segmentfault
咱們把定一個變量的行爲分爲兩個過程,聲明和定義windows
var a = 1 //實際執行的是下面兩步 var a a = 1
var的變量聲明會提高,沒有var就是全局變量,let沒,const有變量提高
var的函數聲明和賦值都提高閉包
a //undefined 由於a的聲明已經提高到最上面了 var a = 1 f() //alert 1 function f () { alert (1) }
有幾個特殊的地方雖然平時不會這麼寫,可是面試題會遇到:
dom
不少人都分不清楚執行環境和做用域的關係。其實很簡單,做用域和上下文徹底是兩個不相干的東西。
做用域是一種規格,聲明函數的時候就已經肯定了。
執行環境是函數執行的時候產生的,函數在執行環境中執行。你們看下面例子函數
alert(a) //a is not defined
執行的時候VO裏面沒有a,由於根據VO做用域鏈【windows】,按照規則找不到a。this
var a = 1 alert(a) // alert 1
執行的時候,根據規則,從VO做用域鏈【windows】頭部window做用域開始找a,找到a了,a爲1,則vo中a設置爲1,因此alert 1spa
var a = 1 function foo() { var a = 100 alert(a) } foo() // alert 100
執行的時候,根據規則,從VO做用域鏈【windows-foo】頭部foo做用域開始找a,找到a了,a爲100,則vo中a設置爲100,因此alert 100
var a = 1 function foo() { alert(a) } foo() // alert 1
執行的時候,根據規則,從VO做用域鏈【windows-foo】頭部foo做用域開始找,沒找到a。根據規則,沿上層做用域(也就是window)開始找,找到a了,a爲1。則vo中a設置爲1,因此alert 1
再說一個通俗一點的的比喻。
我須要找個優秀的音樂老師輔導我彈琴,我在老師的指導下彈琴比如是是函數執行
。
小區這個做用域
找不到好老師,我本市找。
本市這個做用域
找不到好老師,我本省找。
省這個做用域
還找不到好老師,我全國找。
國家這個做用域
還找不到。我就沒辦法了,鋼琴學不會了(函數報錯
)。
若是在小區這個做用域
找到了張老師,我就會在張老師的輔導下學鋼琴,我、張老師、房間、鋼琴構成了學琴的上下文環境
。我學完了,可是我把學琴的這件事告訴了我弟弟,因此張老師的聯繫方式我不能刪掉(閉包
),由於我弟弟指不定哪一天就會要張老師聯繫方式。
爲何閉包上下文不銷燬?
)怎麼實現閉包上下文不銷燬的?
這個得從JS的垃圾收集機制開始講。
js有兩種垃圾收集機制,一種是引用計數(老版IE),還有一種是標記清除
引用計數(淘汰): 只要被引用就+1 ,引用它的變量又被賦值就-1(ie9以前的dom,bom)
存在問題:循環引用 好比dom引用js對象,JS對象(通常能夠是閉包內綁定dom事件)又反過來引用dom,即便此時頁面移除dom,dom也不會被回收,除非兩個手動設置爲null這就形成了內存泄漏
,
標記清除:垃圾收集器在運行時給內存中全部的變量加上標記,而後去掉環境中的變量以及被
環境中變量引用的變量的標記(這也是爲何閉包存在的原用)
。被標記的視爲準備刪除的變量.
正是由於外層上下文有內層上下文中某些東西的引用,因此內層上下文的
標記不清除,在隨後的垃圾收回操做中不被收回銷燬。
1.函數傳參本質
解析可參考:https://segmentfault.com/a/11...
var ary = [1,2,3,4]; function sum(ary) {// 私有的; ary[0] =100; ary = [];// 在JS中,遇到{}、[]都會開闢一個新的空間地址 ary[0] = 10; console.log(ary) } sum(ary); // [10] console.log(ary);// [100,2,3,4]
2.特殊變量提高
var foo=1; function bar(){ if(!foo){ var foo=10; } console.log(foo); } bar(); //10
3.做用域、變量提高
console.log(a); var a=12; function fn(){ console.log(a); //注意這裏的a在本執行環境獲取不到,根據做用域鏈搜索全局執行環境的a a=13; //同理修改的也是全局執行環境的a } fn(); console.log(a); // undefined 12 13
console.log(a); var a=12; function fn(){ console.log(a); var a=13; } fn(); console.log(a); // undefined undefined 12