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

資訊專欄INFORMATION COLUMN

關(guān)于javascript 中的高級(jí)定時(shí)器的若干問(wèn)題

zr_hebo / 1942人閱讀

摘要:閉包閉包是指有權(quán)訪問(wèn)另一個(gè)函數(shù)作用域中的變量的函數(shù)當(dāng)某個(gè)函數(shù)被調(diào)用時(shí),會(huì)創(chuàng)建一個(gè)執(zhí)行環(huán)境及相應(yīng)的作用域鏈。要注意通過(guò)第句聲明的這個(gè)方法屬于構(gòu)造函數(shù)生成的對(duì)象,而不屬于構(gòu)造函數(shù)的變量對(duì)象,也就是說(shuō),并不存在于作用域鏈中。

看到評(píng)論里有仁兄建議我試試箭頭函數(shù),真是受寵若驚,本來(lái)寫這篇文章也只是想記錄寫要點(diǎn)給自己日后看的。今天早上看到一篇總結(jié)javascriptthis的文章JavaScript 中的 this !,也同樣提到了箭頭函數(shù)中this的指向問(wèn)題,所以,又對(duì)這篇文章進(jìn)行了完善。

一、問(wèn)題的起源

論壇上看到這樣一道js編程題:要求用閉包實(shí)現(xiàn)每隔5s輸出0-9之間的十個(gè)數(shù)字。這里先給出我寫的最終實(shí)現(xiàn)方案,如下圖:

毫無(wú)疑問(wèn),這里必須要用到定時(shí)器setTimeout或者setInterval,但是考慮到setInterval存在的兩個(gè)問(wèn)題:

某些間隔會(huì)被跳過(guò)

多個(gè)定時(shí)器的代碼執(zhí)行之間的間隔可能會(huì)比預(yù)期的小

所以,用到setInterval的地方一般都是用遞歸調(diào)用setTimeout的方式來(lái)替代,但是關(guān)于這兩個(gè)定時(shí)函數(shù)中的this我之前的理解有些偏差,我知道這里的this指的是全局對(duì)象window,因?yàn)?b>setTimeout和setInterval都是作為全局函數(shù),也就是window對(duì)象的方法存在的。但是這里有兩個(gè)this

第一個(gè)this:setTimeout(this.func, times)

第二個(gè)this: setTimeout(function(){ alert(this)},times);

那到底哪一個(gè)"this"始終指向的是window呢?

二、執(zhí)行環(huán)境、活動(dòng)對(duì)象、變量對(duì)象、作用域鏈、this

首先澄清一下幾個(gè)概念。

執(zhí)行環(huán)境

執(zhí)行環(huán)境定義了變量和函數(shù)有權(quán)訪問(wèn)的其他數(shù)據(jù),決定了它們各自的行為。每個(gè)執(zhí)行環(huán)境都有一個(gè)與之關(guān)聯(lián)的變量對(duì)象,環(huán)境中定義的所有變量和函數(shù)都保存在這個(gè)變量對(duì)象中。

全局執(zhí)行環(huán)境是最外圍的一個(gè)執(zhí)行環(huán)境。根據(jù)ECMAScript實(shí)現(xiàn)所在的宿主環(huán)境不同,表示全局執(zhí)行環(huán)境的對(duì)象也不一樣。在web瀏覽器中,全局執(zhí)行環(huán)境被認(rèn)為是window對(duì)象,因?yàn)樗械娜肿兞亢秃瘮?shù)都是作為window對(duì)象的屬性和方法創(chuàng)建的。某個(gè)執(zhí)行環(huán)境中的代碼執(zhí)行完畢后,該環(huán)境就會(huì)被銷毀,保存在其中的所有變量和函數(shù)也隨之銷毀(全局執(zhí)行環(huán)境直到應(yīng)用程序退出時(shí)才會(huì)銷毀)

每個(gè)函數(shù)都有自己的執(zhí)行環(huán)境。當(dāng)執(zhí)行流進(jìn)入一個(gè)函數(shù)時(shí),該函數(shù)的執(zhí)行環(huán)境就會(huì)被推入一個(gè)環(huán)境棧中。而在函數(shù)執(zhí)行后,棧將其環(huán)境彈出,把控制權(quán)返回給之前的執(zhí)行環(huán)境。

作用域鏈

當(dāng)代碼在一個(gè)環(huán)境中執(zhí)行時(shí),會(huì)創(chuàng)建變量對(duì)象的一個(gè)作用域鏈。
作用域鏈本質(zhì)上是一個(gè)指向變量對(duì)象的指針列表,它只引用,但不實(shí)際包含變量對(duì)象。
作用域鏈的作用,是保證對(duì)執(zhí)行環(huán)境有權(quán)訪問(wèn)的所有變量和函數(shù)的有序性。作用域鏈的最前端,始終都是當(dāng)前執(zhí)行的代碼所在環(huán)境的變量對(duì)象。如果這個(gè)環(huán)境是函數(shù),則將其活動(dòng)對(duì)象作為變量對(duì)象,活動(dòng)對(duì)象在最開(kāi)始時(shí)只包含一個(gè)變量,即arguments對(duì)象(這個(gè)對(duì)象在全局環(huán)境中是不存在的)。作用域鏈中的下一個(gè)變量對(duì)象來(lái)自包含(外部)環(huán)境,而再下一個(gè)變量對(duì)象則來(lái)自再下一個(gè)包含環(huán)境。這樣一直延續(xù)到全局執(zhí)行環(huán)境;全局執(zhí)行環(huán)境的變量對(duì)象始終是作用域鏈中的最后一個(gè)對(duì)象。
標(biāo)識(shí)符解析就是沿著作用域鏈一級(jí)一級(jí)地搜索標(biāo)識(shí)符的過(guò)程。

this

this是一個(gè)對(duì)象,this對(duì)象是在運(yùn)行時(shí)基于函數(shù)的執(zhí)行環(huán)境綁定的。
在全局函數(shù)中,this等于window;而當(dāng)函數(shù)作為某個(gè)對(duì)象的方法調(diào)用時(shí),this等于那個(gè)對(duì)象。
匿名函數(shù)的執(zhí)行環(huán)境具有全局性,其this通常指向window。這是因?yàn)?,每個(gè)函數(shù)再被調(diào)用時(shí)都會(huì)自動(dòng)取得兩個(gè)特殊變量:thisarguments內(nèi)部函數(shù)在搜索這兩個(gè)變量時(shí),只會(huì)搜索到其活動(dòng)對(duì)象為止,因此永遠(yuǎn)不可能訪問(wèn)到外部函數(shù)中的這兩個(gè)變量。

閉包

閉包是指有權(quán)訪問(wèn)另一個(gè)函數(shù)作用域中的變量的函數(shù)
當(dāng)某個(gè)函數(shù)被調(diào)用時(shí),會(huì)創(chuàng)建一個(gè)執(zhí)行環(huán)境及相應(yīng)的作用域鏈。然后用arguments和其他的命名參數(shù)的值來(lái)初始化函數(shù)的活動(dòng)對(duì)象。
閉包的主要用途有:模仿塊級(jí)作用域和私用變量。

變量對(duì)象

變量對(duì)象中保存了當(dāng)前執(zhí)行環(huán)境中定義的所有變量和函數(shù)。
變量對(duì)象是和執(zhí)行環(huán)境綁定的,而this是和函數(shù)運(yùn)行時(shí)所在的執(zhí)行環(huán)境綁定的。比如對(duì)于一個(gè)全局執(zhí)行環(huán)境,其中的"this"指的是該函數(shù)運(yùn)行時(shí)所在的全局執(zhí)行環(huán)境,也就是window;而變量對(duì)象隸屬于這個(gè)函數(shù)創(chuàng)建的局部執(zhí)行環(huán)境。

三、 setTimeoutsetInterval中的this 測(cè)試一

我們先來(lái)做幾個(gè)測(cè)試

測(cè)試1

10行,setTimeout(this.method,500),此時(shí)調(diào)用的是構(gòu)造函數(shù)內(nèi)的method方法,也就是說(shuō)這里的第一個(gè)"this"指向的是構(gòu)造函數(shù)生成的對(duì)象,即是根據(jù)setTimeout調(diào)用時(shí)所在的執(zhí)行環(huán)境確定的。

盡管調(diào)用的是對(duì)象的method方法,但是方法內(nèi)的this(第二個(gè)this)等于window。為什么會(huì)是這樣呢?在看下面一個(gè)測(cè)試

其實(shí),setTimeout 也只是一個(gè)函數(shù)而已,函數(shù)必然有可能需要參數(shù),我們把 this.a 當(dāng)作一個(gè)參數(shù)傳給 setTimeout 這個(gè)函數(shù),就像它需要一個(gè) fun 參數(shù),在傳入?yún)?shù)的時(shí)候,其實(shí)做了個(gè)這樣的操作 fun = this.a,看到?jīng)]有,這里我們直接把 fun 指向 this.a 的引用;執(zhí)行的時(shí)候其實(shí)是執(zhí)行了 fun() 所以已經(jīng)和 obj 無(wú)關(guān)了,它是被當(dāng)作普通函數(shù)直接調(diào)用的,因此 this 指向全局對(duì)象。

測(cè)試2

10行,setTimeout(method,500),此時(shí)調(diào)用的是全局函數(shù)method。因?yàn)椋m然仍在構(gòu)造函數(shù)的局部執(zhí)行環(huán)境內(nèi),但是局部執(zhí)行環(huán)境的變量對(duì)象中并沒(méi)有method方法,所以,在進(jìn)行標(biāo)識(shí)符解析時(shí),沿著作用域鏈在全局執(zhí)行環(huán)境中找到了method方法。

要注意通過(guò)第6this.method=...聲明的這個(gè)方法屬于構(gòu)造函數(shù)生成的對(duì)象,而不屬于構(gòu)造函數(shù)的變量對(duì)象,也就是說(shuō),并不存在于作用域鏈中。

第二個(gè)this仍然等于window。

測(cè)試3

10行,setTimeout(method,500),此時(shí)調(diào)用的是構(gòu)造函數(shù)method。
第二個(gè)this仍然等于window

測(cè)試4

setTimeout第一個(gè)參數(shù)是javascript代碼字符串時(shí),第二個(gè)this仍然等于window。

測(cè)試5

setTimeout第一個(gè)參數(shù)是匿名函數(shù)時(shí),第二個(gè)this仍然等于window。

結(jié)論一

根據(jù)以上測(cè)試,可以得出以下結(jié)論:

setTimeout 中的延遲執(zhí)行函數(shù)中的this (也就是第二個(gè)this)始終指向window。

setTimeout(this.method, minsec)這種形式的this(也就是第一個(gè)this),其指向是根據(jù)上下文的執(zhí)行環(huán)境確定的。

測(cè)試二

該測(cè)試的目的是確定setTimeout 中的延遲執(zhí)行函數(shù)中的變量是如何沿著作用域鏈搜索的。

測(cè)試6

測(cè)試7

測(cè)試8

測(cè)試6和測(cè)試7本質(zhì)上是相同的,因?yàn)楹瘮?shù)名只是一個(gè)指針,指向函數(shù)對(duì)象。
測(cè)試測(cè)試6和測(cè)試7中,console.log(value)中的value都是構(gòu)造函數(shù)局部執(zhí)行環(huán)境中的value值,而console.log(this.value)中的value都是全局執(zhí)行環(huán)境中的value值。

測(cè)試8中的test指向的是全局執(zhí)行環(huán)境中的test,相應(yīng)的的value都是全局執(zhí)行環(huán)境中的value值。

延遲函數(shù)中的變量也是根據(jù)其所在的執(zhí)行環(huán)境上下文來(lái)確定的,符合作用域鏈的標(biāo)識(shí)符解析過(guò)程。

測(cè)試9

兩個(gè)value都指向的是全局執(zhí)行環(huán)境中的value值,因?yàn)?b>console.log(value)語(yǔ)句所在的局部執(zhí)行環(huán)境上下文并沒(méi)有value值。

結(jié)論二

setTimeout 中的延遲執(zhí)行函數(shù)中的變量也是根據(jù)其所在的執(zhí)行環(huán)境上下文來(lái)確定的,符合作用域鏈的標(biāo)識(shí)符解析過(guò)程。

四、嚴(yán)格模式下的this

除了正常運(yùn)行模式,ECMAscript 5添加了第二種運(yùn)行模式:"嚴(yán)格模式"(trict mode)。顧名思義,這種模式使得Javascript在更嚴(yán)格的條件下運(yùn)行。

關(guān)于嚴(yán)格模式的介紹,請(qǐng)移步這里Javascript 嚴(yán)格模式詳解

嚴(yán)格模式所帶來(lái)的語(yǔ)法和行為的改變大致有以下 條:

1.全局變量顯示聲明

2.靜態(tài)綁定

(1).禁止使用with語(yǔ)句

(2).創(chuàng)設(shè)eval作用域

3.增強(qiáng)的安全措施

(1).禁止this關(guān)鍵字指向全局對(duì)象

(2).禁止在函數(shù)內(nèi)遍歷調(diào)用棧,主要是指callerarguments這兩個(gè)函數(shù)對(duì)象屬性。

4.禁止刪除變量,只有configurable(不懂這個(gè)的去看看《javascript高級(jí)教程》中關(guān)于數(shù)據(jù)屬性訪問(wèn)器屬性的介紹)設(shè)置為true的對(duì)象屬性,才能被刪除。

5.顯示報(bào)錯(cuò)

6.重名錯(cuò)誤

(1).對(duì)象不能有重名屬性

(2).函數(shù)不能有重名參數(shù)

7.禁止八進(jìn)制表示法

8.對(duì)arguments對(duì)象的限制

(1).不允許對(duì)arguments賦值

(2).arguments不再追蹤參數(shù)的變化

(3).禁止使用arguments.callee

9.只允許在全局作用域或函數(shù)作用域的頂層聲明函數(shù)

10.保留字

在嚴(yán)格模式的情況下執(zhí)行純粹的函數(shù)調(diào)用,那么這里的的 this 并不會(huì)指向全局,而是undefined.請(qǐng)看如下測(cè)試:

在這個(gè)測(cè)試?yán)又?,匿名的自?zhí)行函數(shù)都返回1,目的是避免函數(shù)返回undefined造成誤解,要知道js的函數(shù)在沒(méi)有明確指定返回值的情況下默認(rèn)是返回undefined,用new調(diào)用的構(gòu)造函數(shù)除外。

在嚴(yán)格模式下,setTimeout 方法在調(diào)用傳入函數(shù)的時(shí)候,如果這個(gè)函數(shù)沒(méi)有指定了的 this,那么它會(huì)做一個(gè)隱式的操作—-自動(dòng)地注入全局上下文,等同于調(diào)用 foo.apply(window) 而非 foo();因此延遲執(zhí)行函數(shù)中的this仍然指向window,而不是undefined.

當(dāng)然,如果我們?cè)趥魅牒瘮?shù)的時(shí)候已經(jīng)指定this,那么就不會(huì)被注入全局對(duì)象,比如: setTimeout(foo.bind(obj), 1);請(qǐng)看如下測(cè)試。

五、箭頭函數(shù)中的this

在 ES6 的新規(guī)范中,加入了箭頭函數(shù)(想了解更多,請(qǐng)移步這里ECMAScript 6 入門),它和普通函數(shù)最不一樣的一點(diǎn)就是 this 的指向.

箭頭函數(shù)中的 this 只和定義它的時(shí)候所在的作用域的 this 有關(guān),而與在哪里以及如何調(diào)用它無(wú)關(guān),同時(shí)它的 this 指向是不可改變的。請(qǐng)看如下測(cè)試。

在執(zhí)行 setTimeout 時(shí)候,我們先是定義了一個(gè)匿名的箭頭函數(shù),關(guān)鍵點(diǎn)就在這,箭頭函數(shù)內(nèi)的 this 執(zhí)行定義時(shí)所在的對(duì)象,就是指向定義這個(gè)箭頭函數(shù)時(shí)作用域內(nèi)的 this,也就是obj.foo中的this(不要誤解為是 setTimeout中的this啊,只不過(guò)是它的實(shí)參而已。),即 obj;所以在執(zhí)行箭頭函數(shù)的時(shí)候,它的 this -> obj.foo 中的 this -> obj;

利用閉包這種固化this的特性,可以完美的解決之前必須用閉包才能給延遲執(zhí)行函數(shù)綁定this的問(wèn)題。

箭頭函數(shù)內(nèi)的this指向不可改變。請(qǐng)看如下測(cè)試。

六、參考

1.談?wù)剆etTimeout的作用域以及this的指向問(wèn)題
2.http://www.jb51.net/article/30858.htm
3.javascript高級(jí)教程
4.JavaScript 中的 this !

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/86628.html

相關(guān)文章

  • JS高級(jí)講解面向?qū)ο螅?,繼承,閉包,正則表達(dá)式,讓你徹底愛(ài)上前端(進(jìn)階二)

    摘要:通過(guò)構(gòu)造函數(shù)得到的實(shí)例對(duì)象內(nèi)部會(huì)包含一個(gè)指向構(gòu)造函數(shù)的對(duì)象的指針。 JavaScript 高級(jí) 學(xué)習(xí)目標(biāo): 理解面向?qū)ο箝_(kāi)發(fā)思想 掌握 JavaScript 面向?qū)ο箝_(kāi)發(fā)相關(guān)模式 掌握在 JavaScript 中使用正則表達(dá)式 面向?qū)ο蠼榻B 程序中面向?qū)ο蟮幕倔w現(xiàn) 在 JavaScript 中,所有數(shù)據(jù)類型都可以視為對(duì)象,當(dāng)然也可以自定義對(duì)象。自定義的對(duì)象數(shù)據(jù)類型就是面向?qū)ο笾?..

    Nino 評(píng)論0 收藏0
  • JS高級(jí)講解面向?qū)ο螅?,繼承,閉包,正則表達(dá)式,讓你徹底愛(ài)上前端(進(jìn)階二)

    摘要:通過(guò)構(gòu)造函數(shù)得到的實(shí)例對(duì)象內(nèi)部會(huì)包含一個(gè)指向構(gòu)造函數(shù)的對(duì)象的指針。 JavaScript 高級(jí) 學(xué)習(xí)目標(biāo): 理解面向?qū)ο箝_(kāi)發(fā)思想 掌握 JavaScript 面向?qū)ο箝_(kāi)發(fā)相關(guān)模式 掌握在 JavaScript 中使用正則表達(dá)式 面向?qū)ο蠼榻B 程序中面向?qū)ο蟮幕倔w現(xiàn) 在 JavaScript 中,所有數(shù)據(jù)類型都可以視為對(duì)象,當(dāng)然也可以自定義對(duì)象。自定義的對(duì)象數(shù)據(jù)類型就是面向?qū)ο笾?..

    source 評(píng)論0 收藏0
  • 從setTimeout-setInterval看JS線程

    摘要:提出標(biāo)準(zhǔn),允許腳本創(chuàng)建多個(gè)線程,但是子線程完全受主線程控制,且不得操作。所以,這個(gè)新標(biāo)準(zhǔn)并沒(méi)有改變單線程的本質(zhì)。事件循環(huán)主線程線程只會(huì)做一件事,就是從消息隊(duì)列里面取消息執(zhí)行消息,再取消息再執(zhí)行。工作線程是生產(chǎn)者,主線程是消費(fèi)者。 最近項(xiàng)目中遇到了一個(gè)場(chǎng)景,其實(shí)很常見(jiàn),就是定時(shí)獲取接口刷新數(shù)據(jù)。那么問(wèn)題來(lái)了,假設(shè)我設(shè)置的定時(shí)時(shí)間為1s,而數(shù)據(jù)接口返回大于1s,應(yīng)該用同步阻塞還是異步?我們...

    elliott_hu 評(píng)論0 收藏0
  • JS程序設(shè)計(jì)高級(jí)技巧

    摘要:關(guān)于定時(shí)器要記住的最重要的事情是指定的時(shí)間間隔表示何時(shí)將定時(shí)器的代碼添加到隊(duì)列,而不是何時(shí)實(shí)際執(zhí)行代碼。多個(gè)定時(shí)器之間的執(zhí)行間隔會(huì)比預(yù)期的小解決辦法處理中數(shù)組分塊,,函數(shù)節(jié)流,實(shí)際進(jìn)行處理的方法實(shí)際執(zhí)行的代碼初始處理調(diào)用的方法 一、高級(jí)函數(shù) 安全類型檢測(cè) Object.protitype.toString.call(value) 作用域安全的構(gòu)造函數(shù) function Pers...

    Codeing_ls 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<