JavaScript的this和閉包

做爲OO語言,c++、c#或者Java等語言,都有this的概念,JavaScript中存在this的概念,通常編程語言的this就是對象本身,而JavaScript的this卻不必定!javascript

在JavaScript中,this所引用的對象(不少書籍叫函數上下文,我也這樣叫吧)並非由聲明函數的方式決定的,而是由調用函數的方式決定的,下面看代碼:java

var o1 = {handle : 'o1' } ;
var o2 = {handle : 'o2' } ;
var o3 = {handle : 'o3' } ;
window. handle = 'window' ;

function whoAmI ( ) {
return this. handle ;
}

o1. identifyMe = whoAmI ;

alert (whoAmI ( ) ) ; // 輸出window
alert (o1. identifyMe ) ; // 輸出o1
alert (whoAmI. call (o2 ) ) ; // 輸出o2
alert (whoAmI. apply (o3 ) ) ; // 輸出o3

以上輸出說明了下面幾個問題:c++

  • 當直接把函數做爲頂層函數來調用時,函數上下文是window;
  • 當把函數做爲對象的屬性來調用時,該對象就成爲函數調用的函數上下文;
  • 使用Function的call()方法把函數上下文設置爲傳入call()的第一個參數的任何對象,這時該傳入對象成爲函數調用的函數上下文;

順便補充介紹下Function類的call()和apply()方法,它們都是用來調用函數的。
(1)call()方法編程

call(thisObject[, parameter])c#

參數thisObject是一個類,指定函數體內this關鍵字的值,該參數是必須的;
參數parameter是可選的,是要傳遞給函數的參數,能夠指定0或多個參數(參數爲用逗號分隔的列表)。數組

(2)apply()方法網絡

apply(thisObject[, argArray])閉包

與call不一樣的是,第二個參數是用數組模式來傳遞的。app

下面是閉包的內容了(下面部份內容參考於網絡)編程語言

簡單說下什麼是閉包:

  • 閉包就是函數的局部變量集合,只是這些局部變量在函數返回後會繼續存在;
  • 閉包就是就是函數的「堆棧」在函數返回後並不釋放,咱們也能夠理解爲這些函數堆棧並不在棧上分配而是在堆上分配;
  • 當在一個函數內定義另一個函數就會產生閉包;

上面的第二定義是第一個補充說明,抽取第一個定義的主謂賓——閉包是函數的「局部變量」集合。只是這個局部變量是能夠在函數返回後被訪問。(這個不是官方定義,可是這個定義應該更有利於你理解閉包)。

作爲局部變量均可以被函數內的代碼訪問,這個和靜態語言是沒有差異。閉包的差異在於局部變變量能夠在函數執行結束後仍然被函數外的代碼訪問。這意味着函數必須返回一個指向閉包的「引用」,或將這個」引用」賦值給某個外部變量,才能保證閉包中局部變量被外部代碼訪問。固然包含這個引用的實體應該是一個對象,由於在Javascript中除了基本類型剩下的就都是對象了。惋惜的是,ECMAScript並無提供相關的成員和方法來訪問閉包中的局部變量。可是在ECMAScript中,函數對象中定義的內部函數(inner function)是能夠直接訪問外部函數的局部變量,經過這種機制,咱們就能夠以以下的方式完成對閉包的訪問了。

請看如下代碼:

function hello ( name ) {
var text = 'hello ' + name ;
return function ( ) { alert (text ) ; }
}
var sayHello = hello ( 'jack' ) ;
sayHello ( ) ; // 這裏經過閉包訪問到了hello()中的text參數

再看一段定時器代碼

$ ( function ( ) {
var local = 1 ;
window. setInterval ( function ( ) {
alert (local ) ; // 這裏經過閉包訪問到了local變量
local ++;
} , 1000 ) ;
} ) ;

另外,閉包有一個重要的特徵:函數上下文毫不會被包含爲閉包的一部分。例以下面的代碼不會按照咱們指望的方式執行:

// ...
this. id = 'someID' ;
$ ( '*' ). each ( function ( ) {
alert ( this. id ) ;
} ) ;

每一個函數調用都有其函數上下文(this指向的對象),所以上面的代碼,傳遞給each()的函數上下文在回調函數內是來自於jQuery包裝集的元素,而不是被設置爲」someID」的外部函數屬性。對回調函數的每一個調用都會依次彈出警告框,用來顯示包裝集中各個元素的id。

若是須要訪問在外部函數中做爲函數上下文的對象,能夠考慮一般的習慣用法:在局部變量中建立this引用的副本,這個副本將會被包含在閉包中。

// ...
this. id = "someID" ;
var _that = this ;
$ ( '*' ). each ( function ( ) {
alert (_that. id ) ;
} ) ;
相關文章
相關標籤/搜索