国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

筆記:javascript 深入理解

everfight / 1347人閱讀

摘要:所有作為參數傳入的值都會成為對象的數組元素執行上下文的生命周期創建階段在這個階段中,執行上下文會分別創建變量對象,建立作用域鏈,以及確定的指向。

JavaScript深入之從原型到原型鏈

構造函數->原型
每個函數都有一個 prototype 屬性,指向實例的原型
原型:每一個JavaScript對象(null除外)在創建的時候就會與之關聯另一個對象,這個對象就是我們所說的原型
實例->原型
每一個JavaScript對象(除了 null )都具有的一個屬性,叫__proto__,這個屬性會指向該對象的原型
ES5的方法,可以獲得對象的原型
(Object.getPrototypeOf(person) === Person.prototype person是實例,Person是構造函數
當讀取實例的屬性時,如果找不到,就會查找與對象關聯的原型中的屬性,如果還查不到,就去找原型的原型,一直找到最頂層為止。
原型->構造函數
每個原型都有一個 constructor 屬性指向關聯的構造函數
實例-> 構造函數
person.constructor === Person 從原型上面繼承
Null代表什么
null 表示“沒有對象”,即該處不應該有值。

obj.__proto__ :非標準的方法訪問原型,并不存在于 Person.prototype 中,并不是原型上的屬性,它是來自于 Object.prototype,返回了Object.getPrototypeOf(obj)
繼承:
繼承意味著復制操作, 默認并不會復制對象的屬性,在兩個對象之間創建一個關聯,通過委托訪問另一個對象的屬性和函數,所以與其叫繼承,委托的說法反而更準確些。

JavaScript深入之詞法作用域和動態作用域

作用域:定義變量的區域,確定當前執行代碼對變量的訪問權限
Js: 詞法作用域(lexical scoping),也就是靜態作用域,函數的作用域基于函數創建的位置
靜態作用域:作用域在函數定義
動態作用域:作用域是在函數調用

    var scope = "global scope";
    function checkscope(){
        var scope = "local scope";
        function f(){
            return scope;
        }
        return f();
    }
    checkscope();
    
    var scope = "global scope";
    function checkscope(){
        var scope = "local scope";
        function f(){
            return scope;
        }
        return f;
    }
    checkscope()();

思考:結果一樣,有什么不同
JavaScript深入之執行上下文棧

當執行一段代碼的時候,會進行一個“準備工作
這個“一段一段”中的“段”究竟是怎么劃分的呢
Js引擎遇到一段怎樣的代碼時才會做“準備工作”呢?
執行到一個函數的時候,就會進行準備工作,就叫做"執行上下文(execution context)"

Js 的可執行代碼(executable code)的類型
全局代碼、函數代碼、eval代碼

執行上下文棧(Execution context stack,ECS
管理創建執行上下文 ECStack = []
Js解釋執行代碼,最先遇到全局代碼,so初始化首先就會向執行上下文棧壓入一個全局執行上下文, globalContext ,只有當整個應用程序結束的時候,ECStack 才會被清空,所以程序結束之前ECStack 最底部永遠有個 globalContext
當執行一個函數的時候,就會創建一個執行上下文,并且壓入執行上下文棧,當函數執行完畢的時候,就會將函數的執行上下文從棧中彈出

函數執行結束之后,如果沒有顯示地返回值,默認是undefined,chrome中會把函數執行的結果打印出來

JavaScript深入之變量對象

執行上下文,都有三個重要屬性

變量對象(Variable object,VO)

作用域鏈(Scope chain)

this

變量對象:數據作用域,存儲了在上下文中定義的變量和函數聲明

不同上下文變量對象不同:全局上下文下的變量對象和函數上下文下的變量對象

全局上下文中的變量對象:全局對象
全局對象:

預定義的對象
訪問所有其他所有預定義的對象、函數和屬性
頂層 JavaScript 代碼中,可以用關鍵字 this 引用全局對象, 全局對象是作用域鏈的頭
全局對象是由 Object 構造函數實例化的一個對象

全局上下文中的變量對象:活動對象(activation object, AO)
活動對象和變量對象其實是一個東西
它們其實都是同一個對象,只是處于執行上下文的不同生命周期
變量對象:規范上的實現,不可在 JavaScript 環境中訪問
活動對象:只有到當進入一個執行上下文中,這個執行上下文的變量對象才會被激活而只有被激活的變量對象也就是活動對象上的各種屬性才能被訪問
活動對象是在進入函數上下文時刻被創建的,它通過函數的 arguments 屬性初始化。arguments 屬性值是 Arguments 對象

JS 引擎在分析代碼的時候,分為兩個階段:編譯階段和執行階段

編譯階段:處理聲明語句,所有聲明的變量添加為當前執行上下文變量對象(VO)的屬性。如果是變量聲明,其值暫且初始化為 undefined,如果是函數聲明,它會在堆上開辟內存,并將函數定義放到堆上,函數變量只保存這指向函數定義的地址。

執行階段:編譯結束后,JS 引擎會再次掃描代碼,這個階段主要的任務是根據執行語句,更新變量對象等。

當進入執行上下文時,這時候還沒有執行代碼,
變量對象會包括:

函數的所有形參 (如果是函數上下文)

由名稱和對應值組成的一個變量對象的屬性被創建

沒有實參,屬性值設為 undefined

函數聲明

由名稱和對應值(函數對象(function-object))組成一個變量對象的屬性被創建

如果變量對象已經存在相同名稱的屬性,則完全替換這個屬性

變量聲明

由名稱和對應值(undefined)組成一個變量對象的屬性被創建;

如果變量名稱跟已經聲明的形式參數或函數相同,則變量聲明不會干擾已經存在的這類屬性

在代碼執行階段,會順序執行代碼,根據代碼,修改變量對象的值

全局上下文的變量對象初始化是全局對象

函數上下文的變量對象初始化只包括 Arguments 對象

在進入執行上下文時會給變量對象添加形參、函數聲明、變量聲明等初始的屬性值

在代碼執行階段,會再次修改變量對象的屬性值

補充:
Arguments對象 - 調用函數時,會為其創建一個Arguments對象,并自動初始化局部變量arguments,指代該Arguments對象。所有作為參數傳入的值都會成為Arguments對象的數組元素

執行上下文的生命周期

創建階段

在這個階段中,執行上下文會分別創建變量對象,建立作用域鏈,以及確定this的指向。

代碼執行階段

創建完成之后,就會開始執行代碼,這個時候,會完成變量賦值,函數引用,以及執行其他代碼

AO 實際上是包含了 VO 的
也就是說 AO 的確是在進入到執行階段的時候被激活,但是激活的除了 VO 之外,還包括函數執行時傳入的參數和 arguments 這個特殊對象。
AO = VO + function parameters + arguments

在進入執行上下文時,首先會處理函數聲明,其次會處理變量聲明,如果變量名稱跟已經聲明的形式參數或函數相同,則變量聲明不會干擾已經存在的這類屬性。

在進入執行上下文階段,只會將有 `var,function修飾的變量或方法添加到變量對象中。在進行執行階段前一刻,foo和bar方法的它們的VO中均沒有a屬性。在執行階段,執行到 a= 1時,才將a變量添加到全局的變量對象中而不是在進入執行上下文階段。所以foo方法中會報錯,bar方法會打印 1。

function foo() {
    console.log(a);
    a = 1;
}
foo(); // Uncaught ReferenceError: a is not defined

function bar() {
    a = 1;
    console.log(a);
}
bar(); // 1

WT: let/const 在esc中的表現
JavaScript深入之作用域鏈

當查找變量的時候,會先從當前上下文的變量對象中查找,如果沒有找到,就會從父級(詞法層面上的父級)執行上下文的變量對象中查找,一直找到全局上下文的變量對象,也就是全局對象。這樣由多個執行上下文的變量對象構成的鏈表就叫做作用域鏈

函數創建:
函數的作用域在函數定義的時候就決定了
函數有一個內部屬性 [[scope]],當函數創建的時候,就會保存所有父變量對象到其中
[[scope]] 就是所有父變量對象的層級鏈([[scope]] 并不代表完整的作用域鏈!)

function foo() {
    function bar() {
        ...
    }
}

創建時
foo.[[scope]] = [
  globalContext.VO
];

bar.[[scope]] = [
    fooContext.AO,
    globalContext.VO
];

函數激活:
當函數激活時,進入函數上下文,創建 VO/AO 后,將活動對象添加到作用鏈的前端
這時候執行上下文的作用域鏈,我們命名為 Scope:
Scope = [AO].concat([[Scope]]);
e.g.:

var scope = "global scope";
function checkscope(){
    var scope2 = "local scope";
    return scope2;
}
checkscope();

執行過程如下:
1.checkscope 函數被創建,保存作用域鏈到 內部屬性[[scope]]

checkscope.[[scope]] = [
    globalContext.VO
];

2.執行 checkscope 函數,創建 checkscope 函數執行上下文,checkscope 函數執行上下文被壓入執行上下文棧

ECStack = [
    checkscopeContext,
    globalContext
];

3.checkscope 函數并不立刻執行,開始做準備工作,第一步:復制函數[[scope]]屬性創建作用域鏈

checkscopeContext = {
    Scope: checkscope.[[scope]],
}

4.第二步:用 arguments 創建活動對象,隨后初始化活動對象,加入形參、函數聲明、變量聲明

checkscopeContext = {
    AO: {
        arguments: {
            length: 0
        },
        scope2: undefined
    },
    Scope: checkscope.[[scope]],
}

5.第三步:將活動對象壓入 checkscope 作用域鏈頂端

checkscopeContext = {
    AO: {
        arguments: {
            length: 0
        },
        scope2: undefined
    },
    Scope: [AO, [[Scope]]]
}

6.準備工作做完,開始執行函數,隨著函數的執行,修改 AO 的屬性值

checkscopeContext = {
    AO: {
        arguments: {
            length: 0
        },
        scope2: "local scope"
    },
    Scope: [AO, [[Scope]]]
}

7.查找到 scope2 的值,返回后函數執行完畢,函數上下文從執行上下文棧中彈出

ECStack = [
    globalContext
];

補充:
每一個函數都有自己的執行環境,函數執行的時候,會創建函數執行上下文

在源代碼中當你定義(書寫)一個函數的時候(并未調用),js引擎也能根據你函數書寫的位置,函數嵌套的位置,給你生成一個[[scope]],作為該函數的屬性存在(這個屬性屬于函數的)。即使函數不調用,所以說基于詞法作用域(靜態作用域)。
然后進入函數執行階段,生成執行上下文,執行上下文你可以宏觀的看成一個對象,(包含vo,scope,this),此時,執行上下文里的scope和之前屬于函數的那個[[scope]]不是同一個,執行上下文里的scope,是在之前函數的[[scope]]的基礎上,又新增一個當前的AO對象構成的。
函數定義時候的[[scope]]和函數執行時候的scope,前者作為函數的屬性,后者作為函數執行上下文的屬性。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/98242.html

相關文章

  • [筆記] 深入理解 JavaScript Array.sort()

    摘要:以上涉及到一個字符的轉換問題,這里不多擴展,寫一段代碼運行過程做筆記中國代表字符中的第一位,是只有長度的字符輸出字符長度為不確定時放入一個數組中。第一次運行后,返回值為,小于,所以的索引值未變化,。 Array.sort() 方法排序,默認為升序排序,如 1,2,3,4 這樣的排列,可以傳一個對比方法做為排序的參數,也可以不傳,則為按照字符的逐個 unicode 排序。 簡單默認排序 ...

    QLQ 評論0 收藏0
  • 深入理解ES6筆記(十一)Promise與異步編程

    摘要:回調函數模式類似于事件模型,因為異步代碼也會在后面的一個時間點才執行如果回調過多,會陷入回調地獄基礎可以當做是一個占位符,表示異步操作的執行結果。函數可以返回一個,而不必訂閱一個事件或者向函數傳遞一個回調函數。 主要知識點:Promise生命周期、Promise基本操作、Promise鏈、響應多個Promise以及集成PromiseshowImg(https://segmentfaul...

    RayKr 評論0 收藏0
  • 深入理解ES6》筆記——導讀

    摘要:最近買了深入理解的書籍來看,為什么學習這么久還要買這本書呢主要是看到核心團隊成員及的創造者為本書做了序,作為一個粉絲,還是挺看好這本書能給我帶來一個新的升華,而且本書的作者也非常厲害。 使用ES6開發已經有1年多了,以前看的是阮一峰老師的ES6教程,也看過MDN文檔的ES6語法介紹。 最近買了《深入理解ES6》的書籍來看,為什么學習ES6這么久還要買這本書呢?主要是看到Daniel A...

    Godtoy 評論0 收藏0
  • 深入理解JavaScript

    摘要:深入之繼承的多種方式和優缺點深入系列第十五篇,講解各種繼承方式和優缺點。對于解釋型語言例如來說,通過詞法分析語法分析語法樹,就可以開始解釋執行了。 JavaScript深入之繼承的多種方式和優缺點 JavaScript深入系列第十五篇,講解JavaScript各種繼承方式和優缺點。 寫在前面 本文講解JavaScript各種繼承方式和優缺點。 但是注意: 這篇文章更像是筆記,哎,再讓我...

    myeveryheart 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<