《你不知道的JavaScript》-- 精讀(二)

知識點

1.詞法階段

詞法做用域就是定義在詞法階段的做用域。簡單說,詞法做用域是由你在寫代碼時將變量和塊做用域寫在哪裏來決定的,所以當詞法分析器處理代碼時會保持做用域不變(大部分狀況下)。瀏覽器

// 全局做用域,只有一個標識符:foo
function foo(a){
// foo所建立的做用域,三個標識符:b,a,bar
    var b = a * 2;
    function bar(c){
    // bar所建立的做用域,只有一個標識符:c
        console.log(a,b,c);
    }
    bar(b * 3);
}
foo(2);  // 2,4,12
複製代碼

做用域氣泡由其對應的做用域代碼寫在哪裏決定,它們是逐級包含的。 沒有任何函數能夠部分地同時出如今兩個父級函數中。bash

2.查找

做用域氣泡的結構和相互之間的位置關係給引擎提供了足夠的位置信息,引擎用這些信息來查找標識符的位置。函數

做用域查找會在找到第一個匹配的標識符時中止。在多層的嵌套做用域中能夠定義同名的標識符,產生「遮蔽效應」。性能

全局變量會自動成爲全局對象(好比瀏覽器中的window對象)的屬性,所以能夠經過window.a的方式進行訪問那些被同名變量所遮蔽的全局變量。但非全局變量被遮蔽的時候是沒辦法訪問到的 學習

不管函數在哪裏被調用,也不管它如何被調用,它的詞法做用域都只由函數被聲明時所處的位置決定。優化

3.欺騙詞法

欺騙詞法做用域會致使性能降低。ui

1.eval

JavaScript中的eval()函數能夠接受一個字符串爲參數,能夠在你寫的代碼中用程序生成代碼並運行,就好像代碼是寫在那個位置的同樣。spa

eval()進行欺騙詞法的原理就是:在運行期修改書寫期的詞法做用域code

function foo(str,a){
    eval(str); // 欺騙
    console.log(a,b); 
}
var b = 2;
foo("var b = 3",1); // 1,3
複製代碼
在嚴格模式下,eval()在運行時有本身的詞法做用域
function foo(str){
    "use strict";
    eval(str);
    console.log(a); // ReferenceError:a is not defined
}
foo("var a = 2");
複製代碼

setTimeout()和setInterval()也能夠實現跟eval()同樣的效果。對象

2.with

with一般被看成重複引用同一個對象中的多個屬性的快捷方式,能夠不須要重複引用對象,例如:

var obj = {
    a: 1,
    b: 2,
    c: 3
}
// 改值
obj.a = 2;
obj.b = 3;
obj.c = 4;
// with改值
with(obj){
    a = 3;
    b = 4;
    c = 5;
}
複製代碼

考慮以下代碼:

function foo(obj){
    with(obj){
        a = 2;
    }
}
var o1 = {
    a: 3
}
var o2 = {
    b: 3
}
foo(o1);
console.log(o1.a); // 2

foo(o2);
console.log(o2.a); // undefined
console.log(a); // 2 -- a 被泄露到全局做用域
複製代碼

with塊能夠將一個對象處理爲詞法做用域,可是這個塊內部正常的var聲明並不會被限制在這個塊做用域中,而是被添加到with所處的函數做用域中。

總結

1.詞法做用域意味着做用域是由書寫代碼時函數聲明的位置決定的。編譯的詞法分析階段基本可以知道所有標識符在哪裏以及是如何聲明的,從而可以預測在執行的過程當中如何對它們進行查找。

2.JavaScript「欺騙」詞法做用域的兩個機制:eval()和with,反作用是引擎沒法在編譯時對做用域查找進行優化,致使代碼運行變慢,不建議使用。

巴拉巴拉

工做是什麼?

以一個俗人的角度多是爲了生存,衣食住行,以一個超脫的人的角度多是實現自個人價值,獲得某種榮耀或者昇華,對目前的我來講,工做是什麼,只是工做,這樣說有點偷換概念,明明沒有回答什麼,工做如今是個人生活的一部分,有時候我會由於它開心,有時候會由於它難過,但願本身能作到一個日常心,就像常常被灌輸的只是進城打工,看淡,認真,不較真,與人爲善,技術上多學習,多思考,多總結。

相關文章
相關標籤/搜索