由setTimeout的this講起

版權聲明:本文爲博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/qq_26598303/article/details/52668683

在最近一次面試中,技術官問了setTimeout中this的指向,看了無數遍的this相關的東西,沒想到竟然在這個問題上栽了跟頭……都怪我經驗太少看書太少哎,所以來認真研究了一番這東西。
雖然setTimeout()平時也有用過,但理解得並不深。JavaScript高級程序設計有說:超時調用的代碼都是在全局作用域中執行的,因此函數中的this的值在非嚴格模式下指向window對象,在嚴格模式下是undefined。我認真地測試過一遍,思考過程如下:
這裏寫圖片描述
所以結論是,setTimeout()中,如果是setTimeout(this)這樣的形式,那麼this要看上下文,默認是window;如果setTimeout裏面的函數中的this的話,都統一指向window。
那麼由此想到一個問題,如果像上面的代碼,我想拿到this.name等於“yujiayu”要怎麼做呢?因爲上面的代碼setTimeout裏面的函數中的this指向window,那當然this.name肯定是undefined了。其實到這裏答案就非常簡單了,可以看到第14行代碼的this是指向test1對象的,那隻要我們保存一下這個變量,然後使用閉包就能獲取到它了,因爲閉包可以保存自身當前作用域上的變量(當然這肯定是耗費內存的)。代碼:

function test1() {
   var _this = this; 
    this.name = "yujiayu";
    this.sayName = function() {
          console.log(this.name);
    }
    setTimeout(function () {
      // 由於閉包的原因保存了_this爲test1對象,所以sayName()輸出“yujiayu”
        _this.sayName();     
        },0);
    }
new test1();

至此setTimeout中this的問題就差不多了,然而引申出另外一個問題,就是“爲什麼常用setTimeout模擬setInterval,而不是直接用setInterval”
面試官談到js的執行流:“js是單線程的,setTimeout會將函數放在等待序列中,到達設置的時間節點纔會觸發執行。但如果當前的線程
處於佔用狀態,setTimeout設置的函數並不會按時觸發,而是會等到線程空閒了才被觸發執行。”
按照我的理解,其實js的執行流應該跟我之前看的”Event Loop”是一個意思,這個圖特別好說明這個問題:
這裏寫圖片描述
如果按照上圖EventLoop的說法來理解,就是,定時器會在指定的時間裏,將要執行的東西推進回調隊列裏,但不保證這個時間點去執行這項任務。JS高級程序設計也有說這個事情(慚愧,這本書後面的內容我還沒看到)“如果主程序跟定時器代碼花的時間差不多,就會同時出現跳過間隔且連續運行定時器代碼的情況”,於是需要用setTimeout去模擬setInterval:

setTimeout(function () {
    setTimeout(arguments.callee,500)
},500);

在測試過程中還發現了一個有趣現象:
這裏寫圖片描述

原來加引號的console.log使用的是全局作用域,不加是使用自己作用域,而且看到加了引號的那個,來源是“VM1737”,它寫的時候是排在第一,但輸出出來它卻排到第二……這個有點不科學,相同時間進入隊列,當然是先進先出的原則,這個就不知道怎樣解釋了。這個”VMxxxx”的東西以前也不知道是什麼東西,猜測是開發者工具自帶的的東西,後來在stackoverflow發現有人說:[VM] (scriptId) has no special meaning. It’s a dummy name to help us to distinguish code which are not directly tied to a file name, such as code created using eval and friends.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章