JavaScript中的this關鍵字的幾種用法

JS 裏的 thishtml

  • 在 function 內部被建立
  • 指向調用時所在函數所綁定的對象(拗口)
  • this 不能被賦值,但能夠被 call/apply 改變

1. this 和構造函數

function C(){
    this.a = 37;
    }

    var o = new C();
    console.log(o.a); // logs 37


    function C2(){
    this.a = 37;
    return {a:38};
    }

    var b = new C2();
    console.log(b.a); // logs 38

2. this 和對象

對象內部方法的this指向調用這些方法的對象:node

  • 函數的定義位置不影響其this指向,this指向只和調用函數的對象有關。
  • 多層嵌套的對象,內部方法的this指向離被調用函數最近的對象(window也是對象,其內部對象調用方法的this指向內部對象, 而非window)。
//1:this指向調用函數的對象
    var o = {
        prop: 37,
        f: function() {
            return this.prop;
        }
    };
    console.log(o.f());  //37   this指向o
    var a = o.f;
    console.log(a()):  //undefined  this指向a ,a中沒有定義prop

    var o = {prop: 37};
    function independent() {
        return this.prop;
    }
    o.f = independent;
    console.log(o.f()); // logs 37      this指向o
//2:this指向離被調用函數最近的對象
     var o = {
            prop: 37,
            f: function() {
                return this.prop;
            }
        };
        function independent() {
            return this.prop;
        }
        o.b = {
            g: independent,
            prop: 42
            };
            console.log(o.b.g());   //42    this指向o.b

3. this 和函數

普通函數內部的this分兩種狀況,嚴格模式非嚴格模式es6

//非嚴格模式下,this 默認指向全局對象window
function f1(){
  return this;
}
f1() === window; // true

//而嚴格模式下, this爲undefined
function f2(){
  "use strict"; // 這裏是嚴格模式
  return this;
}
f2() === undefined; // true

4. 全局環境的this

前面提到 this 是 「指向調用時所在函數所綁定的對象」, 這句話拗口但絕對正確,沒有一個多餘的字。
全局環境中有不一樣的宿主對象,瀏覽器環境中是 window, node 環境中是 global。這裏重點說下瀏覽器環境中的 this。
瀏覽器環境中非函數內 this 指向 window瀏覽器

alert(window=== this) // true

所以你會看很不少開源 JS lib 這麼寫緩存

(function() {
        // ...
        
    })(this);

或這樣寫app

(function() {
        // ...
    
    }).call(this);

好比 underscore 和 requirejs,大意是把全局變量 window 傳入匿名函數內緩存起來,避免直接訪問。至於爲啥要緩存,這跟 JS 做用域鏈有關係,讀取越外層的標識符性能會越差。dom

瀏覽器中比較坑人,非函數內直接使用 var 聲明的變量默認爲全局變量,且默認掛在 window 上做爲屬性。函數

var andy = '劉德華'
    alert(andy === window.andy) // true
    alert(andy === this.andy) // true
    alert(window.andy === this.andy) // true

由於這個特性,有些筆試題如requirejs

var x = 10;
    function func() {
        alert(this.x)
    }
    var obj = {
        x: 20,
        fn: function() {
            alert(this.x)
        }
    }
    var fn = obj.fn
    func() // 10
    fn() // 10

沒錯,最終輸出的都是全局的 10。永遠記住這一點:
判斷 this 指向誰,看執行時而非定義時只要函數(function)沒有綁定在對象上調用,它的 this 就是 window性能

5. this和DOM事件

當函數被當作監聽事件處理函數時, 其 this 指向觸發該事件的元素 (針對於addEventListener事件)

// 被調用時,將關聯的元素變成藍色
    function bluify(e){
      //在控制檯打印出所點擊元素
      console.log(this);
      //阻止時間冒泡
      e.stopPropagation();
      //阻止元素的默認事件
      e.preventDefault();      
      this.style.backgroundColor = '#A5D9F3';
    }

    // 獲取文檔中的全部元素的列表
    var elements = document.getElementsByTagName('*');

    // 將bluify做爲元素的點擊監聽函數,當元素被點擊時,就會變成藍色
    for(var i=0 ; i<elements.length ; i++){
      elements[i].addEventListener('click', bluify, false);

6. this和內聯事件

內聯事件中的this指向分兩種狀況:

  • 當代碼被內聯處理函數調用時,它的this指向監聽器所在的DOM元素
  • 當代碼被包括在函數內部執行時,其this指向等同於 函數直接調用的狀況,即在非嚴格模式指向全局對象window, 在嚴格模式指向undefined



    依次點擊上邊的三個按鈕後在控制檯的輸出結果

7. setTimeout & setInterval

對於延時函數內部的回調函數的this指向全局對象window(固然咱們能夠經過bind方法改變其內部函數的this指向)
看下邊代碼及截圖

//默認狀況下代碼
    function Person() {  
        this.age = 0;  
        setTimeout(function() {
            console.log(this);
        }, 3000);
    }

    var p = new Person();//3秒後返回 window 對象
    ==============================================
    //經過bind綁定
    function Person() {  
        this.age = 0;  
        setTimeout((function() {
            console.log(this);
        }).bind(this), 3000);
    }

    var p = new Person();//3秒後返回構造函數新生成的對象 Person{...}


8. this能夠被 call/apply 改變

當函數經過Function對象的原型中繼承的方法 call() 和 apply() 方法調用時, 其函數內部的this值可綁定到 call() & apply() 方法指定的第一個對象上, 若是第一個參數不是對象,JavaScript內部會嘗試將其轉換成對象而後指向它。

例子:

function add(c, d){
    return this.a + this.b + c + d;
    }

    var o = {a:1, b:3};

    add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16

    add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34

    function tt() {
    console.log(this);
    }
    // 返回對象見下圖(圖1)
    tt.call(5);  // Number {[[PrimitiveValue]]: 5} 
    tt.call('asd'); // String {0: "a", 1: "s", 2: "d", length: 3, [[PrimitiveValue]]: "asd"}

9. me/self/that/_this 暫存 this

若是採用 OOP 方式寫 JS 代碼,無可避免的會用到 this,方法內會訪問類的內部屬性(字段),也可能會調用類的另外一個方法。當類的方法內又有一個 function 時,好比瀏覽器端開發常常碰見的給 DOM 元素添加事件,這時若是事件處理器(handler)中的想調用類的一個方法,此時 handler 內的 this 是 dom 元素而非類的當前對象。這個時候,須要把 this 暫存,開發者發揮着本身的聰明才智留下了幾種經典的命名** me, self, that, _this**。如


如:

通常會在每一個方法的第一句就把 this 暫存下來

10. ES5 中新增的 bind 和 this

bind方法在ES5引入, 在Function的原型鏈上, Function.prototype.bind。經過bind方法綁定後, 函數將被永遠綁定在其第一個參數對象上, 而不管其在什麼狀況下被調用。

function f(){
  return this.a;
}

var g = f.bind({a:"azerty"});
console.log(g()); // azerty

var o = {a:37, f:f, g:g};
console.log(o.f(), o.g()); // 37, azerty

11. ES6 箭頭函數=> 和 this

箭頭函數的一個重要特徵就是顛覆了上面的一句話,再貼一次

判斷 this 指向誰,看執行時而非定義時,只要函數(function)沒有綁定在對象上調用,它的 this 就是 window

是的,前面一直用這句話來判斷 this 的指向,在箭頭函數裏前面半句就失效了。箭頭函數的特徵就是,定義在哪,this 就指向那。即箭頭函數定義在一個對象裏,那箭頭函數裏的 this 就指向該對象。以下

var book = {
    author: 'John Resig',
    init:  function() {
        document.onclick = ev => {
            alert(this.author) ; // 這裏的 this 不是 document 了
        }
    }
};
book.init()

對象 book 裏有一個屬性 author, 有一個 init 方法, 給 document 添加了一個點擊事件,若是是傳統的函數,咱們知道 this 指向應該是 document,但箭頭函數會指向當前對象 book。

箭頭函數讓 JS 迴歸天然和簡單,函數定義在哪它 this 就指向哪,定義在對象裏它指向該對象,定義在類的原型上,就指向該類的實例,望文知意這樣更容易理解。
做爲方法的箭頭函數this指向全局window對象,而普通函數則指向調用它的對象

原文參考:
http://www.javashuo.com/article/p-aloxbrqk-mm.html
http://www.cnblogs.com/dongcanliang/p/7054176.html

相關文章
相關標籤/搜索