學習 this 記錄

this 原理

首先,要知道的是 this 是指函數當前的運行環境(上下文)。javascript

咱們都知道 this 是函數運行時所在的環境,但咱們不知道是函數的運行環境究竟是怎麼決定的。java

var obj = {
   fn:function(){
       console.log(this.title); 
   },
   title:"Hello"
}

var fn = obj.fn;
var title = "Hi";

obj.fn() //"Hello"
fn() //"Hi"
複製代碼

上面的例子中,obj.fnfn調用的都是同一個函數,但結果卻不同,這就是咱們上面說的 this 是根據運行時所在環境不一樣致使的,對於 obj.fn 來講,fn 是運行來 obj 環境的,因此this 指向 obj,對於 fn 來講是運行在全局的,所以 this 指向的是全局,也就是 window數據結構

那爲何 obj.fn() 就是在 obj 環境運行的,而一旦 var fn = obj.fn 就變成全局環境了呢?下面讓咱們一點點揭開 this 的神祕面紗。閉包

1. 內存的數據結構

javascript 之全部有 this,是和內存結構有關係的。app

var obj = {fn:5}
複製代碼

以上代碼,將一個對象賦值給變量 obj,在 javascript 的 引擎中會先在內存中,生成一個對象 { fn:5},而後在將這個對象的地址賦給變量 obj函數

就是說,變量 obj 只是存了一個地址,若是要進行取讀操做 obj.fn,那引擎是先從 obj 拿到內存地址,而後在從該地址讀出原始對象,而後返回它的 fn 屬性。ui

原始的對象以相似於字典結構的狀態保存,每個屬性名都對應一個屬性描述對象。拿上面的那個例子的 fn 屬性來看this

注意!fn 屬性的值是保存在屬性描述對象的 value 屬性裏面spa

2. 函數

屬性值不是一個函數的時候很清晰,那若是屬性的值是一個函數呢?3d

var obj = { fn: function(){}};
複製代碼

當對象的屬性值是函數的時候,javascript 引擎會單獨把函數保存在內存中,而後再將函數的地址賦值給 fn 屬性的屬性描述對象的 value 屬性上。

因爲函數是單獨的一個值,因此它能夠在不一樣的環境 ( 上下文 ) 中運行。

var fn = function(){ 
    console.log(this.age);
};

var obj = {
    fn: fn,
    age: 5
};
var age = 10;

//單獨運行時
fn(); //10

//在obj中運行時
obj.fn(); // 5
複製代碼

3. 環境變量

因爲 javascript 容許函數體內,引用當前環境的其餘變量,而變量是有當前的運行環境提供的,那麼因爲函數是能夠在不一樣的運行環境中執行,那就須要一種機制,一種可以在函數體內部得到當前運行環境。so,這時 this 出現了,它的目的就是在函數體內部,指向函數當前的運行環境。

function fn (){
    console.log(age); //由運行環境提供
}

var age= 10";

fn(); //10
複製代碼

以上代碼中的 age 就由該函數運行時所在的環境提供。

再看,下面的例子

function fn(){
    console.log(this.xx);
}

var xx = 10;

var obj = {
    fn: fn,
    xx: 100
}

//單獨運行時
fn()//10

//在obj中運行時
obj.fn()//100
複製代碼
  • 以上代碼中,this.xx 指向運行時所在的環境的 xx。
  • fn() 單獨運行時,this.xx 指向全局環境的 xx。
  • obj.fn() 運行時,則 this.xx 指向的是 obj 環境的 xx。

如今,咱們回到文章中最開始提出的問題,obj.fn() 是經過 obj 找到的 fn,因此就是在 obj 環境執行,一旦 var fn = obj.fn,則 變量 fn 就直接指向了函數自己,因此 fn() 就變成了全局環境執行。

注意!不要忘記,當對象裏的屬性名的值是一個函數的時候,這時,javascript 引擎就報函數單獨保存在內存中,而後把函數地址給了 屬性名的屬性描述對象的value上。

this 使用

this 是 javascript 中的一個關鍵字。
它是在運行時,在函數體內自動生成的一個對象,所以只能在函數體內使用

下面讓咱們直截了當的來看下 this 的幾種使用方式

1. 函數調用

函數的一般用法,這種屬於全局調用,所以這時 this 就表明者全局對象

var x = 1;

function fn(){
    console.log(x); // 變量 x,這時是全局的變量 x
}
fn(); //1
複製代碼

2. 匿名函數的使用

匿名函數執行時,this 表明者全局

var x = 1;
var fn = function(){
    console.log(this.x);
}
fn(); // 1

//經常使用閉包式匿名函數

(function(){
    console.log(this.x)
})() //1
複製代碼

3. 做爲對象調用

當函數做爲對象調用的時候,此時的 this 是這個上級對象

function fn(){
    console.log(this.x); //this 指向 obj
}
var obj = {
    x:1,
    m:fn
}    
obj.m(); // 1 
複製代碼

4. 構造函數使用

當經過構造函數,生成一個新對象時,此時 this 是指這個新對象

function Fn(){
    this.x = 1; 
}
var x = 2; 
var obj = new Fn();
obj.x // 1
複製代碼

5. apply / call 時調用

apply/call 是函數的一個方法,主要就是用來改爲函數調用的,第一個參數就是要改變的對象,所以,this 就是指這第一個參數,若是第一個參數無,那 this 就表明者全局

var x = 1;
function fn(){
    console.log(this.x);
}
var obj = {
    x: 2,
    m:fn
}

obj.m.apply(); // 1
複製代碼

更多詳情請移步 阮一峯老師博文

相關文章
相關標籤/搜索