最近在拜讀《你不知道的js》,而此篇是對於《你不知道的js》中this部分的筆記整理,但願能有效的梳理,而且鞏固關於this的知識點bash
一、this是在運行時進行綁定的,並不是在編寫時綁定,它的上下文取決於函數調用時的各類條件,它指向什麼徹底取決於函數的調用位置;ide
二、this的綁定與函數申明位置無關係,只取決於函數的調用方式;函數
三、當函數被調用時,會建立一個活動記錄,即執行上下文。這包括函數在哪被調用、函數調用方式、傳入的參數信息等。this則爲其記錄的一個屬性,會在函數執行的過程當中用到;ui
首先看一段代碼: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能夠以一種更優雅的方式來傳遞上下文對象,使代碼變得簡潔且易於複用對象
先來看一段代碼:作用域
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的指向
這個問題在某些狀況下是正確的,但也有錯誤的狀況,例:
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在任何狀況下都不指向函數的詞法做用域
詞法做用域:定義在詞法階段的做用域,即由你在寫代碼時將變量和塊做用域寫在哪裏來決定