淺談箭頭函數和setTimeout中的this


箭頭函數會改變this的指向,這個你們看文檔都看到過,但是有沒有具體理解呢?
我發現本身應該可能大概是......emmmm,而後我整理了一遍,增強一下概念吧
順帶再講一下setTimeout這個函數改寫this的概念node

首先分別講一下兩位主角瀏覽器

  • 箭頭函數:都2019年了,你們確定不陌生了,用法很簡單,能夠自行百度,箭頭函數有一個很大的特性是會改寫內部的this指向,那麼實際運用的過程當中你考慮過注意過這個問題嗎?箭頭函數內部的this會指向聲明箭頭函數時所在做用域的this(劃重點!!接下來要記住!)
  • setTimeout:你們確定都用過了,它的第一個參數是一個方法,傳入的這個方法內部的this會被改寫指向window(劃重點!!接下來要記住!)

一向風格,咱們上代碼來看問題函數

// 先給window加一個id,以便於確認以後this的指向
window.id = 0;
// 聲明一個函數fn
const fn = {
  id: 1,
  say: function() {
    console.log('id:', this.id);
  },
  sayArrow: () => {
    console.log('id:', this.id);
  },
  say1: function() {
    setTimeout(function() {
      console.log('id:', this.id);
    }, 1000);
  },
  say2: function() {
    let that = this;
    setTimeout(function() {
      console.log('id:', that.id);
    }, 1000);
  },
  say3: function() {
    setTimeout(() => {
      console.log('id:', this.id);
    }, 1000);
  },
  say4: () => {
    setTimeout(() => {
      console.log('id:', this.id);
    }, 1000);
  },
  say5: () => {
    setTimeout(function() {
      console.log('id:', this.id);
    }, 1000);
  },
};

好了,接下來你們來作題,不要作暈了哈this

fn.say();
fn.sayArrow();
setTimeout(fn.say, 1000);
setTimeout(fn.sayArrow, 1000);
setTimeout(() => fn.say(), 1000);
setTimeout(() => fn.sayArrow(), 1000);
fn.say1();
fn.say2();
fn.say3();
fn.say4();
fn.say5();

以上各自輸出什麼呢?接下來覈對下答案,若是全對,那ojbk了
1 0 0 0 1 0 0 1 1 0 0
若是以爲本身可能沒摸透,能夠多包幾層做用域再試試spa

接下來看代碼講緣由!code

fn.say();
/*
  結果: 1
  緣由: 經過fn調用的say, say是 函數聲明, this指向fn,輸出的是fn.id
*/

fn.sayArrow();
/*
  結果: 0
  緣由: 經過fn調用的say, say是 箭頭函數聲明, this指向箭頭函數聲明時做用域的this,也就是this指向window,輸出的是window.id
*/

setTimeout(fn.say, 1000);
/*
  結果: 0
  緣由: 經過setTimeout調用, setTimeout改寫所傳函數的this, 也就是this指向window,輸出的是window.id
*/

setTimeout(fn.sayArrow, 1000);
/*
  結果: 0
  緣由: 經過setTimeout調用, setTimeout改寫所傳函數的this, 也就是this指向window,輸出的是window.id
*/

setTimeout(() => fn.say(), 1000);
/*
  結果: 1
  緣由: 經過setTimeout調用, 可是fn.say()是被箭頭函數包裹,因此fn.say()調用不受this改變的影響,緣由參考第一句輸出
  ps: 等同於 setTimeout(function () { fn.say(); } , 1000);
*/

setTimeout(() => fn.sayArrow(), 1000);
/*
  結果: 0
  緣由: 同上雷同,具體緣由可參考第二句輸出
  ps: 等同於 setTimeout(function () { fn.sayArrow(); } , 1000);
*/

fn.say1();
/*
  結果: 0
  緣由: setTimeout改寫函數內部的this, 使其指向window, 輸出window.id
*/

fn.say2(); // 1
/*
  結果: 1
  緣由: setTimeout雖然改寫函數內部的this,可是輸出的是that.id,這個that在setTimout外面聲明,指向的是fn,因此輸出fn.id
*/

fn.say3(); // 1
/*
  結果: 1
  緣由: fn.say3函數其內部的this指向的fn,而setTimeout內部傳了一個箭頭函數,箭頭函數內部中的this就指向了fn.say3內的this,也就是fn,最後輸出fn.id
*/

fn.say4(); // 0
/*
  結果: 0
  緣由: fn.say4這個函數自己就是使用箭頭函數聲明,其內部的this指向的是箭頭函數聲明時所在的做用域,即window,並且setTimeout也是傳了一個箭頭函數,這裏面的this指向外層箭頭函數內部中的this,傳引用也指向了window,最後輸出window.id
*/

fn.say5(); // 0
/*
  結果: 0
  緣由: fn.say5用箭頭函數聲明,其內部的this指向window,並且setTimeout也會改寫內部this指向window,最後輸出window.id
*/

其實有一些調用其根本緣由是相同的,可是我我的喜歡各個方面去驗證一下,加深一下印象也好,勿噴
附帶說一嘴,若是有同窗在學node, node內部是沒有window對象的,window是瀏覽器規範,因此具體狀況看你在哪裏用了,不過概念是差很少的對象

寫完以爲這篇文章真的是淺談...好low啊哈哈哈哈,寫給本身看!blog

相關文章
相關標籤/搜索