js函數中的this

前兩篇文章「執行環境和做用域」「js中的閉包」,我對談了執行環境、做用域、做用域鏈和閉包的理解。但當牽涉到對象中的方法時,前面談的東西就不那麼適用了。先來看一個例子:javascript

var name = 'a';
function getName(){
  console.log(name);
}
var o1 ={
  name: 'a1',
  getName: getName
}
var o2 ={
  name: 'a2',
  getName: getName
}
o1.getName()    // 'a'
o2.getName()    // 'a'複製代碼

上面的代碼中,o1.getName()和o2.getName()都輸出‘a’,根據"做用域的規則"很好解釋。但問題是:咱們既然使用了這種方式調用函數,確定更但願gentName方法訪問的是對象內部的‘name’屬性。這時,就須要修改外部定義的getName方法了。前面談過在函數執行時,會動態的建立一個活動對象,這個活動對象,被做爲變量對象,推動執行環境棧中。同時,還會建立「arguments」對象和綁定this對象,arguments對象最爲變量對象的第一個屬性,保存着傳入函數中的參數;this對象根據函數的執行環境動態地綁定。有句很經典的判斷this指向的話:誰調用了函數,this就指向誰。java

這樣,只要把getName函數修改爲下面的代碼,就能夠實現訪問對象中name屬性的效果:數組

function getName(){
  console.log(this.name)
}複製代碼

依靠上面經典的話,能夠在不少狀況下判斷this的指向,但還有一些狀況不使用。下面就分類來講下this。微信

一、純粹的函數調用

這是函數最一般的用法。這時,不論函數是在全局做用域下執行,仍是在函數中執行,this都是指向全局對象,也就是window對象。例如:閉包

var person = 'xiaoming'
function f1(){
  var person = 'xiaohong'
  function f2(){
    console.log(this.person)
  }
  f2()
}
f1();  // 'xiaoming'複製代碼

二、做爲對對象的方法調用

在函數做爲對象的方法調用時,上面的那句經典的話,就很適用了。這裏來看一個很典型的例子:app

var age = 18;
var obj = {
  age : 21,
  fn: functoin(){
    console.log(this.age)
  }
}
(false || obj.fn)()   // 18複製代碼

在上面的代碼中,在對象中的fn方法執行以前,會先執行‘||’運算,至關於:函數

(false || function(){
  console.log(this.age)
})()複製代碼

實際上,也就是fn方法在全局做用域中執行。因此,結果是18。post

三、構造函數

構造函數中的this,指向對象的實例。例如:ui

function People(name){
  this.name = name
}
People.prototyope.sayName() = function(){
  console.log(this.name)
}
var p = new People('張三');

p.name  //‘張三’l
p.sayName  //'張三'複製代碼

四、call、apply和bind

call、apply和bind方法都是函數對象中的方法,用來動態地改變函數中this的指向,只是用法不一樣。call和apply被調用時,不只改變函數中this指向,並且執行該函數,但bind僅僅是改變函數中this的指向,並不執行。以下:this

var x = 2;
var y = 3;
function getY(){
  console.log(this.y)
} 
var o = {
  x: 1,
  y: 4,
  getX: function(){
    console.log(this.x)
  }
}
o.getX.call()    //2
getY.bind(o)()    // 4複製代碼

call、apply和bind方法在未傳入指定對象時,默認傳入window 對象,所以,o.getX.call() 輸出結果是2。使用bind方法時,僅僅改變函數中this指針的指向,而要執行須要在後面添加'()'。call 和 apply方法在使用時,除了第一個指定this對象的參數外,後面還能夠添加原油函數的其餘參數,call方法接受單個參數的羅列,而apply方法接受數組格式的參數(arguments對象也能夠)。以下:

fn.call(o, param1,param2)
fn.call(o,[param1,param2])複製代碼

注意點

  • this的指向是不肯定的,不要在函數中包含多層的this。在必要時,能夠將this賦值給其餘的變量,再使用。例如:self,that等。例如:
    var o = {
    f1:  function() {
          console.log(this);
          var that = this;
          var f2 = function() {
            console.log(that);
          }();
      }
    }
    o.f1()
    // Object
    // Object複製代碼
  • 避免回調函數中的this:回調函數中的this每每會改變指向,最好避免使用。例如:
    var o = new Object();
    o.f = function () {
    console.log(this === o);
    }
    o.f() // true複製代碼
    上面的代碼是沒什麼問題的,但當把 o.f 做爲事件處理的回調函數就不同了。例如:
    $('#button').on('click', o.f);複製代碼

寫在結尾:
若是以爲我寫的文章對你有幫助,歡迎掃碼關注個人公衆號:海痕筆記
微信號:haihenbiji

相關文章
相關標籤/搜索