1. 程式人生 > >JS 閉包以及在閉包中使用 setInterval

JS 閉包以及在閉包中使用 setInterval

     這兩天在寫一個頁面自動重新整理的jquery外掛,寫這個外掛的過程遇到了一個問題,呼叫setInterval的時候,setInterval需要呼叫函式內部的引數變數。

  1. 1 var intervalID = window.setInterval(func, delay[, param1, param2, ...]);
    2 var intervalID = window.setInterval(code, delay);

  第一行我們可以看到,setInverval可以把函式func呼叫的引數作為setInverval的引數傳遞進來,但是下面這句說明卻潑了我一盆冷水:

  Note that passing additional parameters to the function in the first syntax does not work in Internet Explorer. If you want to enable this functionality on that browser you must use a compatibility code (see the 

Callback arguments paragraph).

  也就是說,為setInterval呼叫的func傳遞引數的寫法在IE下無效。IE下測試了一下,執行下面的程式碼:

  1. 1 var func = function(param) {
    2     alert(param);
    3 }
    4 var foo = "success!";
    5 setInterval(func, 3000, foo);

  發現IE10下居然彈出了"success!",說明在IE10下還是有效的,但是IE7,8,9都華麗麗的彈出了"undefined"。在吐槽了官方說明的不準確之後,還得另尋它法。

  那麼你會這樣想,為什麼不直接這樣寫:setInterval('func(foo)', 3000)

,確實,如果foo是定義在window下的變數,那麼肯定正確無誤了。

setInterval使用內部函式

  但是,如果foo是定義在函式內部的呢?比如下面這段程式碼:

  1. 複製程式碼
    1 var outerFunc = function() {
    2     var foo = 'Success!';
    3     var innerFunc = function(param) {
    4         alert(param);
    5     }
    6     setInterval('innerFunc(foo)', 3000);
    7 };
    8 outerFunc();
    複製程式碼

  執行了之後,console會無情的告訴你:Uncaught ReferenceError: foo is not defined

What's wrong?setInterval確確實實是寫在outerFunc裡面啊!不錯,從outerFunc內部讀取foo變數是妥妥的是能讀出來的,但是你確定setInterval('innerFunc(foo)', 3000)foo變數是在outerFunc內部讀取的嗎?

  這裡就涉及到setInterval兩種語法的區別了,第一種setInterval(innerFunc, 3000),相當於做了下面三件事:

  1. var func = innerFunc;將innerFunc傳遞給func形參(其實傳遞的是一個閉包,後面再具體說明)
  2. 程式執行3000ms,這期間繼續執行其他程式碼
  3. 執行func(),但是3000ms以後,func()的執行是在window物件下了,但是func()能取到outerFunc()內部的變數

  也就是說,下面的這段程式碼可以彈出'success!'

  1. 複製程式碼
    1 var outerFunc = function() {
    2     var foo = 'success';
    3     var innerFunc = function() {
    4         alert(foo);
    5     };
    6     setInterval(innerFunc, 3000);
    7 };
    8 outerFunc();
    複製程式碼

  而第二種setInterval('innerFunc(foo)', 3000),只是相當於做了第一種的後面兩件事

  1. 程式執行3000ms,這期間繼續執行其他程式碼
  2. 執行innerFunc(foo),這時候innerFunc(foo)就是在window下執行了,連innerFunc都找不到,foo更不用說了

  結合第一種不能給innerFunc傳遞引數但是卻能讀取outerFunc內部引數的特點,想到用閉包來解決這個問題:

  具體做法是向setInterval(func, delay)傳遞一個閉包:

  1. 複製程式碼
     1 var outerFunc = function() {
     2     var foo = 'success!';
     3     var loop = function() {
     4         innerFunc(foo);
     5     };
     6     var innerFunc = function(param) {
     7         alert(param);
     8     };
     9     setInterval(loop, 3000);
    10 };
    11 outerFunc();
    複製程式碼

  注意,這裡傳遞的是loop()而不是loop。最後彈出'success!',表明setInterval中的閉包有效。

回顧閉包

  A closure is an expression (typically a function) that can have free variables together with an environment that binds those variables (that "closes" the expression).

  Since a nested function is a closure, this means that a nested function can "inherit" the arguments and variables of its containing function. In other words, the inner function contains the scope of the outer function.

只看紅字部分,首先閉包是函式(典型的情況),其次,閉包包含了外部函式的作用域鏈。只要建立了對閉包的引用(var func = loop;或者將loop作為實參傳遞給函式),就相當於變相讀取了外部函式(outerFunc)的變數。

  寫到這裡,感覺setInterval算是閉包的一個典型應用場景了吧(setTimeout同理)。

相關推薦

Javascript之以及例項和常見面試題

一.什麼是閉包 高階程式設計三中:閉包是指有權訪問另外一個函式作用域中的變數的函式.可以理解為(能夠讀取其他函式內部變數的函式) 閉包的作用: 正常函式執行完畢後,裡面宣告的變數被垃圾回收處理掉,但是閉包可以讓作用域裡的 變數,在函式執行完之後依舊保持沒有被垃圾回收處理掉 二. 閉包的例項 // 建立

關於npm無法安裝依賴以及安裝緩慢的解決方法

start sta .net pack 一模一樣 title tps span popu 因為npm的服務器在國外,導致我們使用npm安裝第三方包緩慢。而且有的第三方包是被墻的。 因此,作為墻內人,必須解決這個問題,否則開發起來實在是太坑了! 推薦大家使用淘寶的鏡像(cnp

yum 下載安裝以及依賴

以及 yum安裝軟件 style pan 裝包 res class -s resolv 有時候我在用yum安裝軟件,依賴包比較多,還受網速的影響。所以我們可以將安裝包以及依賴包下載到本地安裝,這樣會快捷很多. yum 提供了這種功能 yum -y install yum-u

如何Spring Boot專案打成JAR以及WAR方式

一、將Spring Boot專案打成JAR包1.先選擇專案的根目錄 IDEA2.在命令視窗cmd中cd  專案路徑→選中路徑的磁碟3.輸入Maven命令 mvn -Dmaven.test.Skip -U clean package4.如果是Maven多層架構  會報錯  找不

基本WEB專案需要匯入哪些Spring以及每個的意思和作用

對於我這種初學者來說,網上查詢的有關Spring專案的資料,全都是直接讓匯入spring所有包,但每個包具體是幹嘛的,用途有用到誰並不是很理解。所有再學習了一段時間之後,我總結了以下的知識點。 對於最基本的WEB專案,我們需要匯入以下Spring包: Spring基本的開發包:

JS 以及使用 setInterval

     這兩天在寫一個頁面自動重新整理的jquery外掛,寫這個外掛的過程遇到了一個問題,呼叫setInterval的時候,setInterval需要呼叫函式內部的引數變數。 1 var intervalID = window.setInterval(func, delay[, param1,

js的理解以及this的理解

閉包其實很好理解,但是由於經常把this和閉包綁在一起,從而加大了理解的難度,如果將他們分開考慮,那就清晰多了。 閉包 閉包並不是js首創,在許多語言中都支援閉包,如schemer、ruby等。如果沒有閉包,像js這樣的支援高階函式特性的語言將是一個噩夢。 靜態作用域 動態作用域 var nam

JS基礎 關於在for迴圈的使用

主要是針對ES5的語法,因為ES6中有塊級作用域了(儘管我不知道為什麼我還一直在用es5的語法) 先展示一段問題程式碼 1 for (var i = 0; i < data.length; i++) { 2 var $btn=$('#iBtn'); 3 $btn.on('c

js同步、異步、回調的執行順序以及的理解

調用 develop 打印 有一個 日誌 ima get 由於 修改 首先,記住同步第一、異步第二、回調最末的口訣 公式表達:同步=>異步=>回調 看一道經典的面試題: for (var i = 0; i < 5; i++) {

js典型題--從開始

變量 傳參 settime lex 機制 details tail logs out 一個不起眼的開始 for(var i=0;i<5;i++){ setTimeout(function () { console.log(i)

js——作用域和

如果 分布式系統 ren 移植 font 寫代碼 一次 運行時 屏蔽 1. js是編譯語言,但是它不是提前編譯,編譯結果不能在分布式系統中移植。大部分情況下,js的編譯發生在代碼執行前的幾微秒(甚至更短) 2. 一般的編譯步驟 分詞/詞法分析:把字符串分解成詞法單元

javascript的作用域以及現象

n) 1.5 函數作用域 log var head clas express immediate 1、 詞法作用域 詞法作用域就是定義在詞法階段的作用域,換句話說,也就是js的作用域時在定義階段決定的,和調用無關。 1.1 作用域沿著作用鏈向上查找 <!DOCTY

js基礎知識:,事件處理,原型

bsp ret asc 原函數 ati tac ons 標識符 構造 閉包:其實就是js代碼在執行的時候會創建變量對象的一個作用域鏈,標識符解析的時候會沿著作用域鏈一級一級的網上搜索,最後到達全局變量停止。所以某個函數可以訪問外層的局部變量和全局變量,但是訪問不了裏層的變量

Python核心編程的四大神獸:叠代器、生成器、以及裝飾器

沒有 vertica 二次 輸出結果 九九乘法 num 很大的 自然 模式 生成器 生成器是生成一個值的特殊函數,它具有這樣的特點:第一次執行該函數時,先從頭按順序執行,在碰到yield關鍵字時該函數會暫停執行該函數後續的代碼,並且返回一個值;在下一次調用該函數執行

python函數嵌套以及的原理

一點 才會 解析器 http 標識 -- return 將不 定義 變量相關—嵌套函數 python允許創建嵌套函數。也就是說我們可以在函數裏面定義函數,而且現有的作用域和變量生存周期依舊不變。 例子: #encoding=utf-8def outer(): name

JS(八)

// 閉包問題   //由於 JavaScript 中,函式是物件,   //物件是屬性的集合,而屬性的值又可以是物件,則在函式內定義函式成為理所當然,如果在   //函式 func 內部宣

js作用域及

1,詞法作用域:程式碼在編寫過程中體現出來的作用範圍,程式碼一旦寫好,不用執行,作用域範圍就已經確定好了。 2,js詞法作用域: 函式允許訪問函式外的資料 整個程式碼結構中只有函式可以限定作用域 作用規則首先使用提升規則分析 如果當前作用規則中有名字了,就不用考慮外面的名字 3,閉包

JS匿名函式和

一、匿名函式 函式是JavaScript中最靈活的一種物件,這裡只是講解其匿名函式的用途。匿名函式:就是沒有函式名的函式 函式定義常規方式 第一種:這也是最常規的一種 function double(x){ return 2 * x; } 第二種:這種方法使

js基礎知識(5)-

閉包的定義很簡單:函式 A 返回了一個函式 B,並且函式 B 中使用了函式 A 的變數,函式 B 就被稱為閉包。 function A() { let a = 1 function B() { console.log(a) } return B } 你是否會疑惑,為什麼函式 A 已經彈出呼

函式物件,名稱空間和作用域以及函式和裝飾器

重點:函式func() 兩層含義:   第一層: func 指函式物件,指向記憶體地址   第二層: 括號表示觸發函式功能 一. 函式物件(可以理解為函式名):在面對物件中,一切皆物件   具體體現:1.函式可以引用        2.可以作為函式的引數        3.可以作為函式返回值