文章出處

關于函數聲明,它的一個重要特征就是函數聲明提升,意思是在執行代碼之間會讀取函數聲明,意思是在執行代碼之前會先讀取函數聲明。這就意味著可以把函數聲明放在調用它的語句

后面。

sayHi();
function sayHi(){
alert("Hi!");
}

理解函數提升的關鍵,就是理解函數聲明與函數表達式之間的區別。

//不要這樣做
if(condition){
function sayHi(){
alert("HI!");
}
}else{
function sayHi(){
alert("Yo!");
}
}

表面上看,以上代碼表示在condition為true時,使用一個sayHi()的定義;否則,就使用另一個定義。實際上,這在ECMSscript中屬于無效語法,JavaScript引擎會嘗試修正錯誤,
將其轉換為合理狀態。不過,如果是使用函數表達式,那就沒什么問題了。

//可以這樣做
var sayHi;
if(condition){
sayHi=function(){
alert("Hi!");
}
}
else{
function sayHi(){
alert("Yo!");
}
}

這個例子不會有什么意外,不同的函數會根據condition被賦值給sayHi.

遞歸

我們知道,argument.callee是一個指向正在執行的函數的指針,因此可以用它來實現對函數的遞歸調用,例如:

function factorial(num){
if(num<=1){
return 1;
}else{
return num*argument.callee(num-1);
}
}

閉包

閉包是指有權訪問另一個函數作用域中的變更的函數。創建閉包的常見方式,就是在一個函數內部創建另一個函數。

function createComparisonFunction(propertyName){
return function(object1,object2){
var value1=object1[propertyName];
var value2=object2[propertyName];
if(value1<value2){
return -1;
} else if(value1>value2){
return 1;
}else{
return 0;
}
}
}

閉包與變更

作用域鏈的這種配置機制引出一個值得注意的副作用,即閉包只能取得包含函數中任何變更的最后一個值。如下面這個例子:

function createFunctions(){
var result=new Array();
for(var i=0;i<10;i++){
result[i]=function(){
return i;
}
}
return result;
}

這個函數會返回一個函數數組。表面上看,似乎每個函數都應該返回自己的索引值,即位置0的函數返回0,位置1的函數返回1,以此類推。但實際上,每個函數都返回10。因為每個
函數作用域鏈中都保存著createFunctions()函數的活動對象(只是保存著對匿名函數function(){return i;}的引用),所以它們返回的都是最后一個i.w但是,我們可以通過創建
另一個匿名函數強制讓閉包的行為符合預期,如下所示:

function createFunctions(){
var result=new Array();
for(var i=0;i<10;i++){
result[i]= function(num){
return function(){
return num;
}
}(i)
}
return result;
}

關于this對象

我們知道,this對象是在運行時基于函數的執行環境綁定的:在全局函數中,this等于window,而當函數被作為某個對象的方法調用時,this等 于那個對象。不過,匿名函數的
執行環境具有全局性,因此,其this對象通過指向window

var name="The Window";
var object={
name:"My Object",
getNameFunc:function(){
return function(){
return this.name;
}
}
}
alert(object.getNameFunc()()); //"The Window" ("在非嚴格模式下")


前面提到過,每個函數在被調用時都會自動取得兩個特殊變更:this和arguments。內部函數在搜索這兩個變量時,只會搜索到其活動對象為止,因此永遠不可能直接訪問外部函數中
的這兩個。不過,把外部作用域中的this對象保存在一個閉包能夠訪問到的變量里,就可以讓閉包訪問該對象了。如下所示:

var name="The Window";
var object={
name:"My Object",
getNameFunc:function(){
var that=this;
return function(){
return this.name;
}
}
}


模仿塊級作用域

如前所述,JavaScript沒有塊級作用域的概念。這意味磁卡在塊語句中定義的變量,實際上是包含在函數中而非語句中創建的,來看下面的例子.

function outputNumbers(count){
for(var i=0;i<count;i++){
alert(i);
}
alert(i); //計數
}


即使像下面這樣錯誤的重新聲明同一個變量,也不會改變它的值。

function outputNumbers(count){
for(var i=0;i<count;i++){
alert(i);
}
var i; //重新聲明變更
alert(i); //計數
}


JavaScript從來不會告訴你是否多次聲明了同一個變量;遇到這種情況,它只會對后續的聲明視而不見。匿名函數可以用來模仿塊級作用域并避免這個問題。
用作塊級作用域的匿名函數的語法如下所示:

(function(){
//這里是塊級作用域
})();

以上代碼定義并立即調用了一個匿名函數。將函數聲明包含在一對圓括號中,表示它實際上是一個函數表達式。而緊隨其后的另一對圓括號會立即調用這個函數。
無論在什么地方,只要臨時需要一些變量,就可以使用私有作用域,例如:

function outputNumbers(count){
(function(){
for(var i=0;i<count;i++){
alert(i);
}
})();
alert(i); //導致一個錯誤!
}

 

 


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()