this是什麼以及如何判斷它

總結下對this的學習與理解

轉眼前端的學習已有一年,平常寫代碼中常常碰到this這個東西。特別是在用vue的時候,this仍是有點多的,哈哈。
在翻閱了一部分書籍和一堆大佬的博客後,決定總結一下這些東西,下面談談我對this的一些理解,若是有錯誤,歡迎你們批評指正。若是能夠給你帶來一些幫助,那是再好不過的了。前端

1.什麼是this

this是在運行時基於函數的執行環境綁定的,它的上下文取決於函數調用時的各類條件。
當一個函數被調用時,會建立一個活動記錄(有時候也稱執行上下文)。這個記錄會包含函數在哪裏被調用,函數的調用方法、出今年入的參數等信息。this就是記錄其中一個屬性,會在函數執行的過程當中用到 --你不知道的JavaScript(上)

this其實是在函數被調用時發生的綁定


2 如何判斷this綁定的對象是什麼

var name = 'window'
const obj1 = {
  
  name:'obj1',
  fn(){
      console.log(this.name)      
  }
}
obj1.fn()//'obj1'
var name = 'window'
const obj1 = {
  
  name:'obj1',
  fn(){
//    "use strict"
   
      console.log(this.name)
       
  }
  
}
const obj2 = {
  name:'obj2',
  fn2:obj1.fn
}
obj2.fn2()//'obj2'
obj1.fn()//'obj1'

#this的綁定與函數聲明的位置沒有聲明的位置沒有任何關係,只取決於函數的調用方式
#通常來講,誰最終調用了函數,那麼它就是this的綁定對象。
那在全局下調用函數,this的綁定對象也就是全局對象vue

var name = 'window'
function fn(){
 
  console.log(this.name)
}
fn()//'window'

下面這種狀況爲何不是輸出window呢?es6

var name = 'window'
function fn(){
 this.name = 'fn'
  console.log(this.name)
}
fn()// 'fn'

也是由於在全局調用這個函數的時候,this.name === window.name就把以前的值給覆蓋了,因此輸出就是 'fn'。app

3. 那麼如何判斷最終是誰調用了函數

函數調用的形式

var name = 'window'
const obj1 = {
  
  name:'obj1',
  fn(){
//    "use strict"
   
      console.log(this.name)
       
  }
  
}
const obj2 = {
  name:'obj2',
  fn2:obj1.fn
}
obj2.fn2()//'obj2'
obj1.fn()//'obj1'

仍是按照上面的代碼爲例,這裏函數

obj2.fn2()//徹底等價於下面的
obj2.fn2.call(obj2)

obj1.fn() 等於 obj1.fn.call(obj1)

一樣的學習

var name = 'window'
function fn(){
 this.name = 'fn'
  console.log(this.name)
}
fn() 等於 fn.call()

這裏面call不傳入參數,既爲undefined。在非嚴格模式下傳入undefined和null,都默認是window。

var name = 'window'
function fn(){
  'use strict' //爲函數開啓嚴格模式
 this.name = 'fn'
  console.log(this.name)
}
fn() //則會報錯,這也一樣說明了函數在js內部調用的形式

改改前面的代碼this

var name = 'window'
const obj1 = {
  
  name:'obj1',
  fn(){
        this.name = 'fn'
      function inFn(){
        console.log(this.name)
      }
       inFn()
  }
  
}

obj1.fn()//'window '

上面的inFn()也等同於inFn.call(),在全局調用它,天然也就是輸出window了。code

關於箭頭函數和定時器

首先箭頭函數是沒有this的 ,它的做用域是和父級的上下文綁定在一塊兒的

var name = 'window'
const obj1 = {
  
  name:'obj1',
  fn(){
        this.name = 'fn'
     inFn= ()=>{
        console.log(this.name)
      }
       inFn()
  }
  
}

obj1.fn()//'fn'

它的this就是上一層第一個包裹它的普通函數的this
因此用call/bind/apply調用箭頭函數的時候,是沒有效果的。對象

var name = 'window'
const obj1 = {
  
  name:'obj1',
  fn(){
        this.name = 'fn'
     inFn= ()=>{
        console.log(this.name)
      }
       inFn()
  }
  
}

obj1.fn.call(window)//'fn'

這也是爲何在es6後,諸如_this=this這類寫愈來愈少的緣由ip

定時器對this的影響

setTimeout()調用的代碼運行在與所在函數徹底分離的執行環境上。這會致使,這些代碼中包含的 this 關鍵字在非嚴格模式會指向 window (或全局)對象,嚴格模式下爲 undefined,這和所指望的this的值是不同的。--MDN

備註:在嚴格模式下,setTimeout( )的回調函數裏面的this仍然默認指向window對象, 並非undefined

this.name = 'window'
function Foo(){
this.name = 'Foo'
  this.fn = function(){
    console.log(this.name)
  }
  this.timer = function(){
    setTimeout(this.fn)
  }
}
var obj = new Foo()

obj.timer()//'window'

可使用call/apply/bind調用改變this綁定對象。

this.name = 'window'
function Foo(){
this.name = 'Foo'
  this.fn = function(){
    console.log(this.name)
  }
  this.timer = function(){
    setTimeout(this.fn.call(this))
  }
}
var obj = new Foo()

obj.timer()//'Foo'

還有箭頭函數

this.name = 'window'

const obj = {
  name:'obj',
  fn(){
    console.log(1)
    setTimeout(()=>{
      console.log(this.name)
    },1000)
  }
}

obj.fn()//'obj'

也就是說從優先級上說,有箭頭函數和定時器就不判斷是否由call/apply/bind調用

new對this的影響

new的優先級很高,在沒有定時器影響的狀況下是最高的

this.name = 'window'
function Foo(){
this.name = 'Foo'
  this.fn = function(){
    console.log(this.name)
  }
  this.timer = function(){
    setTimeout(this.fn)
  }
}
var obj = new Foo()

obj.timer() //'window'定時器

只要是由new調用的,就綁定到新建立的對象,其餘狀況彷佛都沒法再改變this綁定的對象。

1.箭頭函數

function Foo(){
  this.name='Foo'
  this.fn = ()=>{
    console.log(this.name)
  }
  
}

var foo = new Foo()
this.name = 'window'  //設置一下window.name的值      
foo.fn()    //'Foo' 輸出的是實例變量
console.log(this.name)//'window'  並無改變window.name的值

2.call/bind/apply

this.name = 'window'
function Foo(){
  this.name='Foo'
  this.fn = ()=>{
    console.log(this.name)
  }
  
}

var foo = new Foo()

foo.fn.call(window)//'Foo'  
const tes = foo.fn.bind(window)
tes()  //'Foo'

##也就是說判斷一個運行中的this綁定,就要找到這個函數的直接調用位置。 ##按照上面介紹的優先級順序進行判斷即可以找到this的綁定對象。

相關文章
相關標籤/搜索