成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

javascript執(zhí)行機制<一>

codeKK / 492人閱讀

摘要:提示,很顯然,出了循環(huán)的的大括號對應(yīng)的作用域之后,就會被自動銷毀。那么呢,也是這樣么我們來看個例子這段代碼執(zhí)行結(jié)果是估計有人也會比較奇怪。這邊我解釋下執(zhí)行這段代碼的過程。提出了用關(guān)鍵字來代替關(guān)鍵字,具體的話可以參考阮一峰的而教程。

從一道題說起

最近又有人問我下面這道題目,題目是這樣的,首先是一個DOM結(jié)構(gòu)如下:




    
1
2
3
4
5

非常easy的dom結(jié)構(gòu),在來一小段js,如下:

var nodes = document.getElementsByTagName("div");
for(var i = 0,len = nodes.length; i < len; i++){
    nodes[i].onclick = function(){
        console.log(i);
    }
}

好了,問題來了,依次點擊div,結(jié)果是多少?答案并不是1,2,3,4,5,而是點擊任何一個div都會輸出5.

分析

先來說下為什么最后執(zhí)行的結(jié)果都是5.首先我們要明白,js中沒有塊級作用域,講人話,就是js中不存在{}這種代碼塊的東西。各位估計會反駁我說,上面例子中不是明明白白的寫的for(){}這種代碼,怎么這邊就開始說js不存在{}這種東西呢?我先舉個C++的例子吧

int arr[] = {1,2,3,4,5};
vector v = vector(arr,arr+sizeof(arr)/sizeof(int));
for(int i = 0; i < v.size(); i++){
    std::cout << i << std::endl;
}

這么寫是沒有問題的,下面我再加點東西

int arr[] = {1,2,3,4,5};
vector v = vector(arr,arr+sizeof(arr)/sizeof(int));
for(int i = 0; i < v.size(); i++){
    std::cout << i << std::endl;
}
std::cout << i;

這么寫,編譯器直接就報錯了。提示 error: use of undeclared identifier "i",很顯然,出了for循環(huán)的{}的大括號對應(yīng)的作用域之后,i就會被自動銷毀。那么JS呢,也是這樣么?我們來看個例子

for(var i = 0;i< 5;i++){
    console.log(i);
}
console.log(i);

這段代碼執(zhí)行結(jié)果是0,1,2,3,4,5.估計有人也會比較奇怪。這邊我解釋下JS執(zhí)行這段代碼的過程。
首先是變量提升,js把var i = 0;分解成兩句話,var i;i =0;并且把var i;提到最近一個function的頂部,這個時候,這段代碼就變成了這樣

var i;
for(i=0;i<5;i++){
    console.log(i);
}
console.log(i);

這樣各位對于上面執(zhí)行出來的0,1,2,3,4,5估計就沒啥疑問了。
看完這個例子之后,我也希望各位注意下我前面說的js沒有塊級作用域,以及js會做變量提升,把變量的申明提升到最近的一個function的頂部
由于js會做變量提升,自動將變量的申明提升到最近的一個function的頂部,所以{}根據(jù)不會構(gòu)成所謂的塊級作用域,對js里面的變量而言,只有function才會是其作用域。

好了,講完js的變量提升,我們再回頭來看最開始的這個問題。首先是變量提升,提升之后我們得到

var nodes = document.getElementsByTagName("div");
var i;
for(i = 0,len = nodes.length; i < len; i++){
    nodes[i].onclick = function(){
        console.log(i);
    }
}

執(zhí)行過程中,我們對每個node[i]節(jié)點都綁定了一個onclick事件,但是for循環(huán)執(zhí)行的過程中,我們并沒有出發(fā)這個click事件,for循環(huán)執(zhí)行結(jié)束之后,i變?yōu)?。當(dāng)用戶點擊div的時候,這個時候執(zhí)行對應(yīng)的onclick函數(shù),也就是console.log(i),這個時候,會自動找到被js變量提升過的i,所以大家都會輸出5.

解決

總結(jié)下,上面的問題之所以會產(chǎn)生,就是因為所有的onclick事件都去引用被js變量提升的i,那么如果我們想要解決這個問題,應(yīng)該怎么辦呢。一個就是我們可以通過JS的IIFE(immediately-invoked-function-expression)來構(gòu)造一個作用域,讓onclick函數(shù)引用我們構(gòu)造出來作用域里面的i。ok,我們來解決下

var nodes = document.getElementsByTagName("div");
for(var i = 0,len = nodes.length; i < len; i++){
    (function(i){
        nodes[i].onclick = function(){
            console.log(i);
        }
    })(i)
    
}

這種做法把整個綁定事件的過程都給包起來了,由于IIFE會馬上執(zhí)行,for循環(huán)的i相當(dāng)于一個輸入?yún)?shù),在綁定完事件只有,也形成了一個作用域,并且這個作用域中存在一個i的值。

同樣的道理,我再給一種解法,如下:

var nodes = document.getElementsByTagName("div");
for(var i = 0,len = nodes.length; i < len; i++){
    nodes[i].onclick = (function(i){
        return function(){
            console.log(i);
        }
    })(i)
}

除此之外,我們可能會想到,如果js能夠有這種塊級作用于就好了,我們綁定的事件一定是在{}作用域下面,一定可以引用到for循環(huán)中的每個i,而不是應(yīng)用哪個被變量提升的i。ES6提出了用let關(guān)鍵字來代替var關(guān)鍵字,具體的話可以參考阮一峰的而ES6教程。上個代碼,這邊代碼用了一個inbrowser的es6轉(zhuǎn)碼器,可以測試用,如果想要生產(chǎn)環(huán)境中使用需要提前將es6代碼編譯成es5的代碼。






    
1
2
3
4
5
>

引用了一個inbrower級別的es6轉(zhuǎn)碼器。具體可以參考babel-standalone項目.改進后的代碼與原來的代碼的區(qū)別在于,將var i = 0換成了let i = 0.
下面我在看下,通過轉(zhuǎn)碼之后,到底生成了什么樣的js代碼,通過es6轉(zhuǎn)碼器,我們最終生成了如下的代碼

var nodes = document.getElementsByTagName("div");

var _loop = function _loop(i, len) {
    nodes[i].onclick = function () {
        console.log(i);
    };
};

for (var i = 0, len = nodes.length; i < len; i++) {
    _loop(i, len);
}

原來ES6幫我們構(gòu)造了一個function的作用域報過了node[i].onclick的事件綁定過程,跟我們上面的解決方法其實是一樣的!

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/82225.html

相關(guān)文章

  • 詳細(xì)解說JavaScript內(nèi)存管理和GC算法

      JavaScript在創(chuàng)建變量(數(shù)組、字符串、對象等)是自動進行了分配內(nèi)存,而且當(dāng)它沒有被使用的狀態(tài)下,會自動的釋放分配的內(nèi)容;其實這樣基層語言,如C語言,他們提供了內(nèi)存管理的接口,比如malloc()用于分配所需的內(nèi)存空間、free()釋放之前所分配的內(nèi)存空間。  釋放內(nèi)存的過程稱為垃圾回收,例如avaScript這類高級語言可以提供了內(nèi)存自動分配和自動回收,其實這個自動儲存不會占用太多空間...

    3403771864 評論0 收藏0
  • 解析關(guān)于JavaScript事件循環(huán)同步任務(wù)與異步任務(wù)

      學(xué)習(xí)一門知識,有些內(nèi)容必須要提前明白,比如在學(xué)習(xí)js中同步異步的問題前,需要明白,js是單線程的,為什么它得是單線程的呢?現(xiàn)在先從它應(yīng)用的場景來說,就是用來讓用戶與頁面進行交互的吧。假如有js是多線程的,那在這個線程里面,用戶點擊某個按鈕會增加一個DOM節(jié)點,在另一個線程里面,用戶點擊這個按鈕又會刪除一個DOM節(jié)點,那么此時js就不知道該聽誰的了。這就是為什么會出現(xiàn)同步異步。假設(shè)沒有異步,那么...

    3403771864 評論0 收藏0
  • JavaScript數(shù)據(jù)結(jié)構(gòu)與算法

      學(xué)習(xí)JS,就應(yīng)該知道數(shù)據(jù)結(jié)構(gòu)與算法這個詞?,F(xiàn)在我們就說說:  數(shù)據(jù)結(jié)構(gòu)與算法在編程中是十分需要,主要是沒有很好的數(shù)據(jù)結(jié)構(gòu)與算法的功底,就影響后續(xù)學(xué)習(xí)和工作,這是為什么那?是因為隨著項目的復(fù)雜,數(shù)據(jù)量也隨之變大,數(shù)據(jù)結(jié)構(gòu)與算法可以更優(yōu)雅的處理這些數(shù)據(jù)。  程序=數(shù)據(jù)結(jié)構(gòu)+算法,是計算機科學(xué)界的一個經(jīng)典名句,這句話也體現(xiàn)了一個應(yīng)用程序是與數(shù)據(jù)結(jié)構(gòu)和算法密不可分的。  數(shù)據(jù)結(jié)構(gòu)  其實數(shù)據(jù)結(jié)構(gòu)簡單說...

    3403771864 評論0 收藏0
  • 同源策略

    一、瀏覽器安全無風(fēng)險的世界不存在,包括瀏覽器,我們知道Web世界是開放的,包容的。但是開放和風(fēng)險是對立的。Web 世界會是開放的,任何資源都可以接入其中,我們的網(wǎng)站可以加載并執(zhí)行別人網(wǎng)站的腳本文件、圖片、音頻 / 視頻等資源,甚至可以下載其他站點的可執(zhí)行文件。比如你打開了一個銀行站點,然后又一不小心打開了一個惡意站點,如果沒有安全措施,惡意站點就可以做很多事情:修改站點的 DOM、CSSOM 等信...

    社區(qū)管理員 評論0 收藏0
  • useEffect支持async及await如何運用

    背景  在使用useEffect中用啦回調(diào)函數(shù)中使用 async...await... 這時候就會報錯。  上面代碼可以看到,在報錯,effect function 應(yīng)該返回一個銷毀函數(shù)(effect:是指return返回的cleanup函數(shù)),如果 useEffect 第一個參數(shù)傳入 async,返回值則變成了 Promise,結(jié)果就是會導(dǎo)致 react 在調(diào)用銷毀函數(shù)的時候報錯。  React...

    3403771864 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<