JavaScript:遍曆原型鏈,調用棧,範圍鏈)JavaScript:遍曆原型鏈,調用棧,範圍鏈JavaScript:我對原型鏈的理解

來源:互聯網
上載者:User
JavaScript:遍曆原型鏈,調用棧,範圍鏈 

在JavaScript中,有三種常見的鏈式結構:原型鏈(Prototype Chain),調用棧(Call Stack),範圍鏈(Scope Chain).本文並不準備講這些概念的基礎知識,而是要給出如何遍曆這三種鏈結構的方法,從而加深理解.

遍曆原型鏈

在JavaScript中,任何對象都有自己的原型鏈.原型鏈是由一系列對象加上最後的null組成的.如果還沒掌握相關基礎知識,可以看看我在MDN上翻譯的繼承與原型鏈一文.遍曆函數如下:

function getPrototypeChain(obj) {    var protoChain = [];    while (obj = Object.getPrototypeOf(obj)) {        protoChain.push(obj);    }    protoChain.push(null);    return protoChain;}

嘗試執行一下

>getPrototypeChain(new String(""))[String, Object, null]                     //依次是String.prototype,Object.prototype,null  >getPrototypeChain(function(){})[function Empty() {}, Object, null]        //依次是Function.prototype,Object.prototype,null

這個函數是在我以前寫的一篇文章JavaScript:我對原型鏈的理解中給出的.

遍曆調用棧

在JavaScript中,調用棧就是一系列的函數,表明當前函數是由哪些上層函數調用的.遍曆函數如下:

function getCallStack() {    var stack = [];    var fun = getCallStack;    while (fun = fun.caller) {        stack.push(fun)    }    return stack}

該函數用到了非標準的caller屬性,不過主流瀏覽器都支援它.嘗試執行一下:

function a() {    b()}function b() {    c()}function c() {    alert(getCallStack().map(function (fun) {        return fun.name  //使用了非標準的name屬性    }))  }a()  //彈出c,b,a
b()  //彈出c,b

在調試工具中,我們可以直接使用console.trace()來列印出調用棧.在遞迴調用中,如果調用棧的長度過長,引擎就會拋出異常"too much recursion".到底多長是上限,不同的引擎不同的作業系統環境這個值是不同的.可以使用下面這個函數運算式擷取到這個上限值:

> (function(i){try{(function m(){++i&&m()}())}catch(e){return i}})(0)50761
遍曆範圍鏈

範圍鏈是由一系列執行內容(Execution context)中的使用中的物件(Activation object)加最後的全域對象組成的.使用中的物件是一個抽象實體(Abstract Entity),它是由引擎內部來管理的,並不能通過JavaScript來訪問.看不到,摸不著,所以這些知識就很難理解.

不過在Mozilla的引擎中,有一個魔法屬性__parent__可以擷取到函數執行時的使用中的物件.只是在SpiderMonkey中,該屬性已經被刪除了(Firefox 4開始).不過在Mozilla的另外一個JavaScript引擎Rhino(Java編寫)上,還可以使用這個特殊屬性.遍曆代碼如下:

function getScopeChain(fun) {    var scopeChain = [];    while (fun = fun.__parent__) {        scopeChain.push(fun);
} return scopeChain;
}

嘗試執行一下:

var a = 0;(function fun1() {    var a = 1;    (function fun2() {        var a = 2;        (function fun3() {            var a = 3;            getScopeChain(function () {}).map(function (obj) {                print("-----------------------------")                for(var i in obj){                    print(i + ":" + (obj[i].name?obj[i].name:obj[i]))                }            })        })()    })()})()-----------------------------           //函數fun3arguments:[object Arguments]        a:3fun3:fun3-----------------------------           //函數fun2arguments:[object Arguments]a:2fun2:fun2-----------------------------           //函數fun1arguments:[object Arguments]a:1fun1:fun1-----------------------------           //全域上下文a:0getScopeChain:getScopeChain

在JavaScript中,有三種常見的鏈式結構:原型鏈(Prototype Chain),調用棧(Call Stack),範圍鏈(Scope Chain).本文並不準備講這些概念的基礎知識,而是要給出如何遍曆這三種鏈結構的方法,從而加深理解.

遍曆原型鏈

在JavaScript中,任何對象都有自己的原型鏈.原型鏈是由一系列對象加上最後的null組成的.如果還沒掌握相關基礎知識,可以看看我在MDN上翻譯的繼承與原型鏈一文.遍曆函數如下:

function getPrototypeChain(obj) {    var protoChain = [];    while (obj = Object.getPrototypeOf(obj)) {        protoChain.push(obj);    }    protoChain.push(null);    return protoChain;}

嘗試執行一下

>getPrototypeChain(new String(""))[String, Object, null]                     //依次是String.prototype,Object.prototype,null  >getPrototypeChain(function(){})[function Empty() {}, Object, null]        //依次是Function.prototype,Object.prototype,null

這個函數是在我以前寫的一篇文章JavaScript:我對原型鏈的理解中給出的.

遍曆調用棧

在JavaScript中,調用棧就是一系列的函數,表明當前函數是由哪些上層函數調用的.遍曆函數如下:

function getCallStack() {    var stack = [];    var fun = getCallStack;    while (fun = fun.caller) {        stack.push(fun)    }    return stack}

該函數用到了非標準的caller屬性,不過主流瀏覽器都支援它.嘗試執行一下:

function a() {    b()}function b() {    c()}function c() {    alert(getCallStack().map(function (fun) {        return fun.name  //使用了非標準的name屬性    }))  }a()  //彈出c,b,a
b()  //彈出c,b

在調試工具中,我們可以直接使用console.trace()來列印出調用棧.在遞迴調用中,如果調用棧的長度過長,引擎就會拋出異常"too much recursion".到底多長是上限,不同的引擎不同的作業系統環境這個值是不同的.可以使用下面這個函數運算式擷取到這個上限值:

> (function(i){try{(function m(){++i&&m()}())}catch(e){return i}})(0)50761
遍曆範圍鏈

範圍鏈是由一系列執行內容(Execution context)中的使用中的物件(Activation object)加最後的全域對象組成的.使用中的物件是一個抽象實體(Abstract Entity),它是由引擎內部來管理的,並不能通過JavaScript來訪問.看不到,摸不著,所以這些知識就很難理解.

不過在Mozilla的引擎中,有一個魔法屬性__parent__可以擷取到函數執行時的使用中的物件.只是在SpiderMonkey中,該屬性已經被刪除了(Firefox 4開始).不過在Mozilla的另外一個JavaScript引擎Rhino(Java編寫)上,還可以使用這個特殊屬性.遍曆代碼如下:

function getScopeChain(fun) {    var scopeChain = [];    while (fun = fun.__parent__) {        scopeChain.push(fun);
} return scopeChain;
}

嘗試執行一下:

var a = 0;(function fun1() {    var a = 1;    (function fun2() {        var a = 2;        (function fun3() {            var a = 3;            getScopeChain(function () {}).map(function (obj) {                print("-----------------------------")                for(var i in obj){                    print(i + ":" + (obj[i].name?obj[i].name:obj[i]))                }            })        })()    })()})()-----------------------------           //函數fun3arguments:[object Arguments]        a:3fun3:fun3-----------------------------           //函數fun2arguments:[object Arguments]a:2fun2:fun2-----------------------------           //函數fun1arguments:[object Arguments]a:1fun1:fun1-----------------------------           //全域上下文a:0getScopeChain:getScopeChain
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.