關於this

最近在拜讀《你不知道的js》,而此篇是對於《你不知道的js》中this部分的筆記整理,但願能有效的梳理,而且鞏固關於this的知識點bash

1、this是一種怎樣的機制

一、this是在運行時進行綁定的,並不是在編寫時綁定,它的上下文取決於函數調用時的各類條件,它指向什麼徹底取決於函數的調用位置;ide

二、this的綁定與函數申明位置無關係,只取決於函數的調用方式;函數

三、當函數被調用時,會建立一個活動記錄,即執行上下文。這包括函數在哪被調用、函數調用方式、傳入的參數信息等。this則爲其記錄的一個屬性,會在函數執行的過程當中用到;ui

2、this的做用

首先看一段代碼:this

function identify() {
    return this.name.toUpperCase();
}
function speak() {
    var greeting = "Hello, I'm " + identify.call(this);
    console.log(greeting);
}
var me = {
    name: "Mike"
};
var you = {
  name: "Jenny"  
};
identify.call(me); // Mike
identify.call(you); // Jenny

speak.call(me); // Hello, I'm Mike speak.call(you); // Hello, I'm Jenny
複製代碼

這段代碼可在不一樣的上下文對象中重複使用identify(),speak();spa

若不使用this,可將代碼變換以下:code

function identify(con) {
    return con.name.toUpperCase();
}
function speak(con) {
    var greeting = "Hello, I'm " + identify.call(con);
    console.log(greeting);
}
var me = {
    name: "Mike"
};
var you = {
  name: "Jenny"  
};
identify(me); // Mike
speak(you); // Hello, I'm Jenny 複製代碼

this能夠以一種更優雅的方式來傳遞上下文對象,使代碼變得簡潔且易於複用對象

3、對於this的誤解

誤解1、this指向函數自身(僅從字面上理解this的含義)

先來看一段代碼:作用域

function foo(num) {
    console.log("foo: " + num);
    // 記錄foo被調用的次數
    this.count++;
}
foo.count = 0;
var i;
for(i = 0; i < 0; i++) {
    if(i > 5) {
        foo(i);
    }
}
// foo(6);
// foo(7);
// foo(8);
// foo(9);

// foo被調用了幾回?
console.log(foo.count); // 0
複製代碼

爲何此處的foo.count值爲0呢?string

執行foo.count時,的確向函數對象foo添加一個屬性count,但函數內部代碼的this並不是指向foo,而this.count是建立了一個全局變量,因此this指向了window

此時this.count的值爲NaN

若要實現foo.count = 4 ,則將代碼變化以下:

方法1、

function foo(num) {
    console.log("foo: " + num);
    // 記錄foo被調用的次數
    data.count++;
}
var data = {
    count: 0
};
var i;
for(i = 0; i < 0; i++) {
    if(i > 5) {
        foo(i);
    }
}
// foo(6);
// foo(7);
// foo(8);
// foo(9);

// foo被調用了幾回?
console.log(data.count); // 4
複製代碼

此寫法雖然達到了理想的狀態,但卻忽略了this

方法2、

function foo(num) {
    console.log("foo: " + num);
    // 記錄foo被調用的次數
    foo.count++;
}
foo.count = 0;
var i;
for(i = 0; i < 0; i++) {
    if(i > 5) {
        foo(i);
    }
}
// foo(6);
// foo(7);
// foo(8);
// foo(9);

// foo被調用了幾回?
console.log(data.count); // 4
複製代碼

這種寫法一樣迴避了this的問題

方法3、

function foo(num) {
    console.log("foo: " + num);
    // 記錄foo被調用的次數
    this.count++;
}
foo.count = 0;
var i;
for(i = 0; i < 0; i++) {
    if(i > 5) {
        // 使用call(...)能夠確保this指向函數對象foo自己
        foo.call(foo, i);
    }
}
// foo(6);
// foo(7);
// foo(8);
// foo(9);

// foo被調用了幾回?
console.log(data.count); // 4
複製代碼

此方法使用call,改變了上下文對象,強制將this指向foo函數對象

總結:經過以上例子說明,僅僅從字面意思來解釋this是不許確的,而是要經過關注執行上下文,以及函數的調用位置來判斷this的指向

誤解2、this指向函數的做用域

這個問題在某些狀況下是正確的,但也有錯誤的狀況,例:

function foo() {
    var a = 2;
    this.bar();
}
function bar() {
    console.log(this.a);
}
foo(); // RefrenceError: a is not defined
複製代碼

這段代碼試圖使用this聯通foo()、bar()的詞法做用域,從而讓bar()能夠訪問foo()做用域中的變量。但this不可能在詞法做用域中查到什麼。由於this指向全局,而a屬於foo做用域中的變量,因此沒法查到

總結:this在任何狀況下都不指向函數的詞法做用域

詞法做用域:定義在詞法階段的做用域,即由你在寫代碼時將變量和塊做用域寫在哪裏來決定

相關文章
相關標籤/搜索