Javascript中this基礎應用

前言

如下內容只針對非嚴格模式,嚴格模式區不說了
若是看過《JavaScript高級程序設計(第3版)》的人都應該有印象,裏面關於this對象是這麼形容的segmentfault

this 對象是在運行時基於函數的執行環境綁定的:在全局函數中,this等於window,而當函數被做爲某個對象的方法調用時,this 等於那個對象。不過,匿名函數的執行環境具備全局性,所以其 this 對象一般指向 window。

demo1

示例以下app

var a = 10,
  obj = {
    a: 20
  };

function log() {
  var a = 30;
  console.log(this.a); //依然指向全局
};

console.log(this.a); // 全局
log(); //方法
log.call(obj); //指向obj

;
(function () {
  console.log(this.a) //匿名函數
})()

// 10
// 10
// 20
// 10

目前爲止,一切都符合預期表現。而後咱們再看些複雜點的寫法。函數

demo2

var a = 10,
  obj = {
    a: 20,
    log: function () {
      console.log(this.a); //指向obj
    }
  };

function log() {
  function _log() {
    console.log(this.a); //指向全局
  };
  _log();
};

obj.log(); //調用對象方法
log(); //調用方法內部方法

// 20
// 10

雖然有點繞,可是仍是能夠明白的,this指向調用方法該對象,匿名函數this指向全局
看到這裏咱們好像已經大概明白this是怎麼一回事了,而後咱們再寫複雜點this

demo3

var a = 10,
  obj = {
    a: 20,
    b: this.a + 30
  };
console.log(obj.b); // 40

是否是又猛的懷疑人生了?明明應該this是指向obj得出50,爲何會指向全局得出40的!?
想一想上面說的當函數被做爲某個對象的方法調用時, this 等於那個對象。難道屬性值又是另外一回事?
帶着疑問咱們直接打印出this看看設計

var a = 10,
  obj = {
    a: 20,
    b: this
  };
console.log(obj.b === window); //true

因此屬性值裏的this真的指向全局,因而咱們能夠假設得出一個結論:當函數被做爲某個對象的方法調用時, this 等於那個對象,而某個對象的屬性值的this是直接指向全局的
聽起來好拗口,是否是意思對象的方法this指向對象,屬性值指向全局!?code

demo4

帶着疑問咱們直接看例子對象

var a = 10,
  obj = {
    a: 20,
    log: function () {
      console.log(this.a);
    }
  };
var fn = obj.log;
fn(); //調用賦值方法10

正如前面所說,當函數被做爲某個對象的方法調用時, this 等於那個對象。若是不是該對象直接調用時,this指向調用對象。
基於這個結論,即便中間通過幾層函數調用也同樣的ip

var a = 10,
  obj = {
    a: 20,
    log: function () {
      console.log(this.a); //指向obj
    }
  };

function all_log(fn) {
  fn();
}

all_log(obj.log); // 10

看到了吧,即便通過一箇中間函數調用,實際至關於window調用對象方法,因此this也是指向全局的.原型鏈

demo5

而後看看常常會用到的函數return出的this指向get

var a = 10,
  obj = {
    a: 20,
    log: function () {
      return function () {
        console.log(this.a); //指向??
      }
    }
  };
obj.log()(); //10

衹要基礎稍好也能理解,由於obj.log()返回一個匿名函數,而後至關於在全局下再調用匿名函數,所以this直接指向全局了。書裏官方點的解釋就是

每一個函數在被調用時都會自動取得兩個特殊變量: thisarguments。內部函數在搜索這兩個變量時,只會搜索到其活動對象爲止,所以永遠不可能直接訪問外部函數中的這兩個變量(例子是指obj)

須要注意的是若是沒有明確指向全局的話this實際上都是指向undefined的,衹是非嚴格模式下,它會被自動指向全局對象。

function log() {
  'use strict';
  console.log(this === window);
}

log(); // 獨立調用false
window.log(); // window下調用 true

demo6

書裏還提到一個挺有意思的寫法

var a = 10,
  obj = {
    a: 20,
    log: function () {
      console.log(this.a); //指向??
    }
  };
(obj.log = obj.log)(); //先賦值再調用 10

你會發現竟然this也指向全局了。
由於代碼先執行了一條賦值語句,而後再調用賦值後的結果。由於這個賦值表達式的值是函數自己,因此 this 的值不能獲得維持,結果就返回了10。

demo7

若是是做爲構造函數使用的狀況下

function Person() {
  this.name = 'mike';
  this.log = function () {
    console.log(this);
  }
};

var man = new Person();
man.log();//Person {name: "mike", log: function}

裏面的this是指向new出來的對象,詳情能夠看看我以前寫的博文關於Javascript中的new運算符,構造函數與原型鏈一些理解

demo8

還有種狀況是經過callapply修改this指向,它會強制指向方法的第一個參數

var a = 10,
  obj = {
    a: 20
  };

function log() {
  console.log(this.a);
};

log.call(obj); //指向obj
log.apply(obj); //指向obj

基於上面的狀況,咱們能夠得出幾個結論

1, this 對象是在運行時基於函數的執行環境綁定的2, 若是沒有明確指向全局的話this實際上都是指向undefined的,衹是非嚴格模式下,它會被自動指向全局對象3, 當函數被做爲某個對象的方法調用時,this 等於那個對象4, 當某個對象的屬性值裏的this是直接指向全局對象5, 匿名函數的執行環境具備全局性,所以其 this 對象一般指向全局對象6, 構造函數中的this會指向它實例化對象7, call或apply方法能強制修改this指向方法指定對象

相關文章
相關標籤/搜索