JavaScript學習總結之匿名函數的this指向問題

前言

JavaScript中的this指向問題對於web前端入行不深的人來講是個比較複雜的問題。特寫此文章來記錄今天遇到的關於匿名函數中this指向問題的思考和感悟。前端

問題復現

今天在研究函數防抖場景時看到以下代碼:web

function debounce(fn, delay) {
        var timer; // 維護一個 timer
        return function () {
            var _this = this; // 取debounce執行做用域的this
            var args = arguments;
            if (timer) {
                clearTimeout(timer);
            }
            timer = setTimeout(function () {
                fn.apply(_this, args); // 用apply指向調用debounce的對象,至關於_this.fn(args);
            }, delay);
        };
    }

其中有一段代碼是 var _this = this 這段代碼出如今由return返回的匿名函數中,這個時候我就有些懵逼了,由於根據我匱乏的js知識,這裏的this應該是指向全局做用域纔對,爲何能像註釋那樣指向debounce執行時的做用域呢?感受以下所寫是否更加合理呢?(事實證實這麼寫確定是不對的)閉包

function debounce(fn, delay) {
    var timer
    var _this = this
    return function() {
    ...
    }
}

因而我打算用代碼來實測這裏的 debounce執行做用域中的this到底指的是什麼,它會變化嗎?仍是根據個人理解只要是像相似的匿名函數其中的this都是指向全局的呢?app

因而我寫下以下代碼(關鍵部分):
body部分新增一個button標籤函數

`<button>我是button</button>`

script標籤內部代碼以下:this

//函數防抖
    function debounce(fn, delay) {
        var timer; // 維護一個 timer
        return function () {
            var _this = this; // 取debounce執行做用域的this
            var args = arguments;
            if (timer) {
                clearTimeout(timer);
            }
            timer = setTimeout(function () {
                fn.apply(_this, args); // 用apply指向調用debounce的對象,至關於_this.fn(args);
            }, delay);
        };
    }
    

    var btn = document.getElementsByTagName('button')[0]

    btn.onclick= debounce(function() {
        console.log(this)
    }, 1000)

點擊按鈕,看看控制檯輸出this究竟是誰,按照我以前的理解輸出的this應該是window全局對象纔對
console.pngspa

出乎意料,這裏的this輸出的是button元素,因而我再在上述腳本中新增一個事件綁定:code

window.onclick = debounce(function() {
        console.log(this)
    }, 1000)

點擊頁面空白處輸入以下:
console2.png
此次輸出的就是window了! 看來這裏的this實際是跟debounce函數所返回函數的實際調用者有關,第一次控制檯輸出的是button元素,由於是經過button元素來調用該返回函數,第二次調用者就是widnow,舉這段btn.onclick = dobounce(function() {console.log(this)}, 1000) 代碼的例子:對象

  1. 頁面初始化完畢後,執行腳本代碼, debounce函數接收一個具體函數(將其命名爲fn好了)和一個時間間隔參數(intervcal)
  2. 進到debounce代碼內部,return 一個匿名函數,並賦給btn.onclick,實際上就是事件綁定
  3. 因此說當我點擊button的時候,btn.onclick的執行代碼是這樣的:
btn.onclick = function() {
    var _this = this; // 取debounce執行做用域的this
    var args = arguments;
    if (timer) {
        clearTimeout(timer);
    }
    //由於閉包的存在timer仍是取的debounce中的timer
    timer = setTimeout(function () {
        fn.apply(_this, args); // 用apply指向調用debounce的對象,至關於_this.fn(args);
    }, delay);
}

那麼這裏的this指向的就是button元素了,爲何呢,emmm寫了太多了,打算專門再寫一篇總結來延伸this的指向問題,今天的總結到此結束!blog

相關文章
相關標籤/搜索