前言
理解javascript的指針就需要先了解js的執行環境和作用域!執行環境的定義了變量或函數有權訪問的其他數據,決定了它們各自的行為。每個執行環境都有一個與之關聯的變量對象,環境中定義的所有的變量和函數都保存在這個對象中。雖然我們編寫的代碼無法訪問這個對象,但解析器在處理數據時會在后臺使用它。
1、全局執行環境
全局執行環境是最外圍的一個執行環境,根據js實現的宿主環境的不同,表示執行環境的對象也不一樣。在web瀏覽器中認為window就是全局執行的對象。因此所有的全局變量和函數都是作為window對象進行創建的。某個執行環境中的所有代碼執行完畢后,該環境被銷毀,保存在其中的所有的變量和函數定義也會被銷毀。每個函數都有自己的執行環境,當執行流進入一個函數的時候,函數的環境就會被推入一個環境棧中。而在函數執行之后,棧將其環境彈出。
2、作用域鏈
當代碼在一個環境中執行時候,會創建變量的一個作用域鏈(scope chain)。作用域鏈的用途,是保證對執行環境有權訪問的所有的變量和函數的有序訪問。作用域鏈的前端,始終都是當前執行的代碼所在的環境的變量對象,如果這個環境是函數,則將其活動對象作為變量對象。活動對象在最開始的時候只包含一個變量,arguments對象。作用域鏈的下一個對象來自包含(外部)環境,而再下一個對象則來自下一個包含對象,這樣一直延續到全局。
JavaScript由于其在運行期進行綁定的特性,JavaScript 中的 this 可以是全局對象、當前對象或者任意對象,這完全取決于函數的調用方式。JavaScript 中函數的調用有以下幾種方式:作為對象方法調用,作為函數調用,作為構造函數調用,和使用 apply 或 call 調用。
看下面第一個例子
var point = {?
? ? ? x : 0,?
? ? ? y : 0,?
? ? ?moveTo : function(x, y) {?
? ? ? ? ? ? ? ? ? ? ?console.log(this);//1
? ? ? ? ? ? ? ? ? ? ?this.x = this.x + x;?
? ? ? ? ? ? ? ? ? ? ?this.y = this.y + y;?
? ? ? ? ? ? ?}?
? ?};
point.moveTo(1,1); //this 綁定到當前對象,即point對象
console.log(point);//2
第一個位置上的this我們打印的時候發現這里的this指向就是point 這個對象!
point.moveTo()這個方法執行后就更改了對象point的屬性x和y
第二個例子
function func(x) {?
? ? ? ?this.x = x;
? ? ? console.log(this);
}?
func(2);
我們發現這個時候的this指向是window ?why?
這個很好理解,func(2) 可以寫成window.func(2);由于任何函數或者全局的屬性都是window對象下面的,那么這里的this當然就是window
第三個例子
var point = {?
? ? ? x : 0,?
? ? ? y : 0,?
? ? ? moveTo : function(x, y) {?
? ? ? ? ? ? ? ? ? ? ? // 內部函數
? ? ? ? ? ? ? ? ? ? ?var moveX = function(x) {?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? console.log(this);
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? this.x = x;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? };?
? ? ? ? ? ? ? ? ? ? ?// 內部函數
? ? ? ? ? ? ? ? ? ? ?var moveY = function(y) {?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? this.y = y;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?console.log(this);
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? };?
? ? ? ? ? ? ? ? ? ? moveX(x);?
? ? ? ? ? ? ? ? ? ? console.log(moveX() in point);//false
? ? ? ? ? ? ? ? ? ? console.log(moveX() in window);//true
? ? ? ? ? ? ? ? ? ? moveY(y);?
? ? ? ? ? }?
};?
point.moveTo(1,1);?
point.x; //=>0?
point.y; //=>0
上面的代碼我們分析下很好理解!執行point.moveTo(1,1)里面有兩個方法,moveX和moveY,這兩個方法并沒有綁定到對象point上,我們知道所有的方法都是屬于window對象的,那么這里的moveX和moveY實際上是window上調用的,并不是屬于point對象!
第四個例子
function Point(x,y){?
? ? ? ? ? console.log(this);//第一次是通過new創建的,返回的是Point{} 它是一個對象,不是單純的方法了
? ? ? ? ? this.x = x; // this ?
? ? ? ? ?this.y = y; // this ?
}
var np=new Point(1,1);//所以這里可以理解成這樣
/*
? ? ? ? ? ?var np = {
? ? ? ? ? ? ? ? ? ? ? x = 1,
? ? ? ? ? ? ? ? ? ? ? y =1
? ? ? ? ? ? ? ?};
*/
np.x;//1
var p=Point(2,2);//這個時候不是通過new創建,就相當于window.Point(2,2),它就綁定到window上了!所以this指向window
console.log(p);//由于函數Point沒有返回值,所以這里的p = undefined
p.x;//error, p是一個空對象undefined
總結:
調用形式 | this指向 |
---|---|
普通函數 | 全局對象window |
對象的方法 | 該對象 |
構造函數 | 新構造的對象 |
文章參考地址:
http://www.cnblogs.com/isaboy/?
http://www.cnblogs.com/isaboy/archive/2015/10/29/javascript_this.html