成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

JavaScript函數(shù)表達(dá)式——“函數(shù)的遞歸和閉包”的注意要點

winterdawn / 3130人閱讀

摘要:如調(diào)用函數(shù)聲明函數(shù)不會報錯使用函數(shù)表達(dá)式則不可以報錯創(chuàng)建函數(shù)的兩種方式,一個是函數(shù)聲明如第一種方式一個是函數(shù)表達(dá)式如第二種方式。第二種函數(shù)創(chuàng)建方式創(chuàng)建的函數(shù)叫匿名函數(shù)或拉姆達(dá)函數(shù),因為關(guān)鍵字后面沒有標(biāo)識符。

函數(shù)表達(dá)式的基本概念 name屬性和函數(shù)提升

首先,name屬性,通過這個屬性可以訪問到給函數(shù)指定的名字。(非標(biāo)準(zhǔn)的屬性)如:

function People(){};
console.log(People.name); //People

其次,函數(shù)聲明提升,意味著可以把函數(shù)聲明放在調(diào)用它的語句后面。如:

sayHi(); //調(diào)用函數(shù)
function sayHi(){ //聲明函數(shù)
    console.log("Hi");
} //不會報錯

使用函數(shù)表達(dá)式則不可以:

sayHi();
var sayHi = function(){
    console.log("Hi");
} //報錯

創(chuàng)建函數(shù)的兩種方式,一個是函數(shù)聲明(如第一種方式);一個是函數(shù)表達(dá)式(如第二種方式)。第二種函數(shù)創(chuàng)建方式創(chuàng)建的函數(shù)叫“匿名函數(shù)”或“拉姆達(dá)函數(shù)”,因為function 關(guān)鍵字后面沒有標(biāo)識符。

函數(shù)提升的常見錯誤

需要注意的是,作為對比,下面的兩種代碼中,第一個是錯誤的(會導(dǎo)致各瀏覽器出現(xiàn)不同的問題);第二個才使正確的。代碼如下:

var condition = true;
if (condition){
    function sayHI(){
        console.log("hi")
    }
    sayHI(); //"hello"
}else{
    function sayHI(){
        console.log("hello")
    }
    sayHI();
}

報錯

var condition = false;
var sayHi;
if(condition){
    sayHi = function(){
        console.log("hi")
    };
    sayHi();
}else{
    sayHi = function(){
        console.log("hello")
    };
    sayHi(); //hello
}

沒有錯誤

var condition = true;
if(condition){
    var sayHi = function(){
        console.log("hi")
    };
    sayHi(); //hi
}else{
    var sayHi = function(){
        console.log("hello")
    };
    sayHi(); //hello
}

這里也不會出現(xiàn)問題。出現(xiàn)上面問題的根源就是函數(shù)提升,就是函數(shù)聲明和函數(shù)表達(dá)式之間的區(qū)別所導(dǎo)致的。

函數(shù)的遞歸

遞歸函數(shù)就是在一個函數(shù)通過名字調(diào)用自身的情況下構(gòu)成的。如:

function factorial(num){
    if(num <= 1){
        return 1;
    }else{
        return num * factorial(num - 1);
    }
}    
console.log(factorial(4)); //24 4*3*2*1

但是,函數(shù)里面包含了函數(shù)自身所以,在應(yīng)該使用arguments.callee來解決該問題。如:

function factorial(num){
    if(num <= 1){
        return 1;
    }else{
        return num * arguments.callee(num - 1);
    }
}    
console.log(factorial(4)); //24 4*3*2*1

但如果使用上面這種方法,則在嚴(yán)格模式下行不通。不過可以使用命名函數(shù)表達(dá)式來達(dá)成相同的結(jié)果。如:

var factorial = (
    function f(num){
        if(num <= 1){
            return 1;
        }else{
            return num * f(num - 1);
        }
    }
);    
console.log(factorial(4)); //24 4*3*2*1

即,把它包含在一個變量里面,在遇到其他這種需要使用arguments.callee的時候都可以這樣做。

函數(shù)的閉包

閉包就是有權(quán)訪問另一個函數(shù)作用域中的變量的函數(shù)。常見的創(chuàng)建閉包的方式就是在一個函數(shù)內(nèi)部創(chuàng)建另一個函數(shù)。在此之前應(yīng)該先掌握作用域鏈的概念(見《Javascript執(zhí)行環(huán)境和作用域的注意要點》一文《Javascript執(zhí)行環(huán)境和作用域的注意要點》)

作用域鏈

以下面的代碼為例

function compare(value1,value2){
    if (value1 > value2){
        return 1;
    }else if (value1 < value2){
        return -1;
    }else {
        return 0;
    }
}
var result = compare(5,10);

調(diào)用函數(shù)compare時,函數(shù)執(zhí)行環(huán)境中的作用域鏈:

作用域鏈本質(zhì)上是一個指向變量對象的指針列表。

另一個例子:

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;
        }
    };
}
var compare = createComparisonFunction("name");
var result = compare({name: "Nicholas"},{name: "Greg"});

這個就相當(dāng)于:

var compare = function(object1,object2){
    var value1 = object1["name"];
    var value2 = object2["name"];
    
    if (value1 < value2){
        return -1;
    }else if(value1 > value2){
        return 1;
    }else{
        return 0;
    }
};
var result = compare({name: "Nicholas"},{name: "Greg"});

相當(dāng)于:

var result = function(){
    var value1 = {name: "Nicholas"}["name"];
    var value2 = {name: "Greg"}["name"];
    
    if (value1 < value2){
        return -1;
    }else if(value1 > value2){
        return 1;
    }else{
        return 0;
    }
};
console.log(result()); //1

所以,完整的代碼如下:

var compareNames = createComparisonFunction("name");

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;
        }
    };
}

var result = compareNames({name: "Nicholas"},{name: "Greg"});

compareNames = null;

調(diào)用compareNames()函數(shù)的過程中產(chǎn)生的作用域鏈之間的關(guān)系圖如下:

常見的閉包的模式一般都是這樣:

var X = function A(a){
    return function(b1,b2){...a...} //匿名函數(shù)
};    
var Y = X(b1,b2);

舉個例子:

var obj1 = {
    name: "co",
    color: ["white","black"]
};
var obj2 = {
    name: "lor",
    color: ["yellow","red"]
};

function displayProperty(propertyName){
    return function(obj1,obj2){
        var value1 = obj1[propertyName];
        var value2 = obj2[propertyName];
        
        if(typeof value1 === "string"){
            return value1 + " and " + value2 + "
"; }else if(value1 instanceof Array){ return value1.toString() + "
" + value2.toString(); }else{ return false; } }; } var displayP = displayProperty("name"); var displayStr = displayP(obj1,obj2); document.write(displayStr); displayP = null; var displayP = displayProperty("color"); var displayStr = displayP(obj1,obj2); document.write(displayStr); /* co and lor white,black yellow,red */

閉包會攜帶他包含的函數(shù)的作用域,因此會更多的占用內(nèi)存資源,建議只有在絕對必要的時候再考慮使用閉包。V8 優(yōu)化后的js 引擎會嘗試收回被閉包占用的內(nèi)存。

閉包與變量

閉包的副作用是閉包只能取得包含函數(shù)中任何變量的最后一個值。

this對象

全局函數(shù)中this = window;當(dāng)函作為位某個對象的方法調(diào)用時this = 那個對象;但是匿名函數(shù)的執(zhí)行環(huán)境又全局性,this 通常指向window;但也有例外:

var name = "the window";

var obj = {
    name: "the obj",
    
    getNameFunc: function(){
        return function(){
            return this.name;
        };
    }
};

console.log(obj.getNameFunc()()); //"the window" 別忘了要寫兩個小括號

因為每個函數(shù)在被調(diào)用的時候都會自動取得兩個特殊的變量:this 和arguments;內(nèi)部函數(shù)在搜索這兩個變量時,只會搜索到其活動對象為止。

var obj = {
    name: "Oliver",
    age: 18,
    friends: ["alice","troy"],
    sayName: function(){
        return this.name;
    },
    sayFriends: function(){
        return function(){
            return this.friends;
        };
    }
    
};

console.log(obj.sayFriends()()); //undefined

上面這個代碼就是因為閉包的問題,導(dǎo)致錯誤。又如:

var friends = "window"s friends";

var obj = {
    name: "Oliver",
    age: 18,
    friends: ["alice","troy"],
    sayName: function(){
        return this.name;
    },
    sayFriends: function(){
        return function(){
            return this.friends;
        };
    }
    
};

console.log(obj.sayFriends()()); //window"s friends 匿名函數(shù)執(zhí)行環(huán)境的全局性

解決這個問題的方法是:

var friends = "window"s friends";

var obj = {
    name: "Oliver",
    age: 18,
    friends: ["alice","troy"],
    sayName: function(){
        return this.name;
    },
    sayFriends: function(){
        var outer = this;
        return function(){
            return outer.friends;
        };
    }
    
};

console.log(obj.sayFriends()()); //["alice","troy"] 這樣就可以正常搜索到了

又如:

var friends = "window"s friends";

var obj = {
    name: "Oliver",
    age: 18,
    friends: ["alice","troy"],
    sayWindowFriends: function(){
        return function(){
            return this.friends;
        };
    },
    sayFriends: function(){
        var outer = this;
        return function(){
            return function(){
                return function(){
                    return outer.friends
                };
            };
        };
    }
};

console.log(obj.sayWindowFriends()()); //"window"s friends"
console.log(obj.sayFriends()()()()); //["alice", "troy"]

再舉個例子:

var obj = {
    name: "Oliver",
    age: 18,
    friends: ["alice","troy"],
    sayFriends: function(i){
        var outer = this;
        return function(j){
            return outer.friends[i] + outer.friends[j];
        };
    }
};

console.log(obj.sayFriends(0)(1)); //alicetroy

另外,在幾種特殊情況下,this 的值可能會發(fā)生改變。如:

var name = "the window";

var obj = {
    name: "my object",
    
    getName: function(){
        return this.name;
    }
};

console.log(obj.getName()); //my object
console.log((obj.getName)()); //my object 與上面的是相同的,多了個括號而已
console.log((obj.getName = obj.getName)()); //the window

只要不用下面兩種方式調(diào)用函數(shù)即可。

內(nèi)存泄露

經(jīng)過上面的一番折騰,最明顯的就是window.name 一直占用內(nèi)存,無法清空。必須手動把它清理掉,用window.name = null來操作。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/78219.html

相關(guān)文章

  • JavaScript函數(shù)達(dá)式——“函數(shù)模仿塊級作用域及函數(shù)私有變量”注意要點

    摘要:模仿塊級作用域在塊級語句中定義的變量,實際上是包含函數(shù)中而非語句中創(chuàng)建的。避免對全局作用域產(chǎn)生不良影響這種方式可以通過創(chuàng)建私有作用域,避免對全局作用域產(chǎn)生不良影響。一般包括函數(shù)的參數(shù)局部變量和內(nèi)部定義的其他函數(shù)。 模仿塊級作用域 在塊級語句中定義的變量,實際上是包含函數(shù)中而非語句中創(chuàng)建的。如: function outputNumbers(x){ for (var i = 0;...

    archieyang 評論0 收藏0
  • JavaScript引用類型——“單體內(nèi)置對象”注意要點

    摘要:單體內(nèi)置對象單體內(nèi)置對象就是開發(fā)人員不必顯式地實例化內(nèi)置對象,因為他們已經(jīng)實例化了。前面的章節(jié)討論過了大多數(shù)內(nèi)置對象,還定義了兩個單體內(nèi)置對象和。 單體內(nèi)置對象 單體內(nèi)置對象就是開發(fā)人員不必顯式地實例化內(nèi)置對象,因為他們已經(jīng)實例化了。前面的章節(jié)討論過了大多數(shù)內(nèi)置對象,ECMA-262 還定義了兩個單體內(nèi)置對象:Global 和Math。 Global 對象 所有在全局作用域中定義的屬性...

    xushaojieaaa 評論0 收藏0
  • JavaScript引用類型——“Function類型”注意要點

    摘要:類型每個函數(shù)都是類型的實例。如以上代碼可行,是因為在代碼開始值錢,解析器就已經(jīng)通過一個名為函數(shù)聲明提升的過程,讀取并將函數(shù)聲明添加到執(zhí)行環(huán)境中去。也可同時使用函數(shù)聲明和函數(shù)表達(dá)式,但在瀏覽器中會出錯。 Function 類型 每個函數(shù)都是Function 類型的實例。函數(shù)名實際上就是一個指向函數(shù)對象的指針,不會與某個函數(shù)綁定。 函數(shù)聲明方式創(chuàng)建Function,語法如下: functi...

    fantix 評論0 收藏0
  • JavaScript引用類型——“RegExp類型”注意要點

    摘要:類型通過類型來支持正則表達(dá)式。如由于構(gòu)造函數(shù)的模式參數(shù)是字符串,所以在某些情況下要對字符串進行雙重轉(zhuǎn)義。而第二個循環(huán)使用構(gòu)造函數(shù)在每次循環(huán)沖創(chuàng)建正則表達(dá)式。如另外,還有個用于存儲捕獲組的構(gòu)造函數(shù)屬性。 EegExp 類型 ECMAScript 通過RegExp 類型來支持正則表達(dá)式。語法如下: var expression = / pattern / flags; 每個正則表達(dá)式都可...

    mochixuan 評論0 收藏0
  • 深入理解javascript原型閉包

    摘要:深入理解原型和閉包王福朋博客園深入理解原型和閉包一切都是對象原文鏈接本文要點一切引用類型都是對象,對象是屬性的集合。每個對象都有一個,可稱為隱式原型。另外注意,構(gòu)造函數(shù)的函數(shù)名第一個字母大寫規(guī)則約定。 深入理解javascript原型和閉包 王福朋 - 博客園 —— 《 深入理解javascript原型和閉包》 1. 一切都是對象 原文鏈接:http://www.cnblogs.com...

    jemygraw 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<