亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

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

winterdawn / 3180人閱讀

摘要:如調(diào)用函數(shù)聲明函數(shù)不會(huì)報(bào)錯(cuò)使用函數(shù)表達(dá)式則不可以報(bào)錯(cuò)創(chuàng)建函數(shù)的兩種方式,一個(gè)是函數(shù)聲明如第一種方式一個(gè)是函數(shù)表達(dá)式如第二種方式。第二種函數(shù)創(chuàng)建方式創(chuàng)建的函數(shù)叫匿名函數(shù)或拉姆達(dá)函數(shù),因?yàn)殛P(guān)鍵字后面沒(méi)有標(biāo)識(shí)符。

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

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

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

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

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

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

sayHi();
var sayHi = function(){
    console.log("Hi");
} //報(bào)錯(cuò)

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

函數(shù)提升的常見(jiàn)錯(cuò)誤

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

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

報(bào)錯(cuò)

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

沒(méi)有錯(cuò)誤

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

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

函數(shù)的遞歸

遞歸函數(shù)就是在一個(gè)函數(shù)通過(guò)名字調(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來(lái)解決該問(wèn)題。如:

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)格模式下行不通。不過(guò)可以使用命名函數(shù)表達(dá)式來(lái)達(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

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

函數(shù)的閉包

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

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

另一個(gè)例子:

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

這個(gè)就相當(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ù)的過(guò)程中產(chǎn)生的作用域鏈之間的關(guān)系圖如下:

常見(jiàn)的閉包的模式一般都是這樣:

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

舉個(gè)例子:

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 */

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

閉包與變量

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

this對(duì)象

全局函數(shù)中this = window;當(dāng)函作為位某個(gè)對(duì)象的方法調(diào)用時(shí)this = 那個(gè)對(duì)象;但是匿名函數(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" 別忘了要寫(xiě)兩個(gè)小括號(hào)

因?yàn)槊總€(gè)函數(shù)在被調(diào)用的時(shí)候都會(huì)自動(dòng)取得兩個(gè)特殊的變量:this 和arguments;內(nèi)部函數(shù)在搜索這兩個(gè)變量時(shí),只會(huì)搜索到其活動(dòng)對(duì)象為止。

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

上面這個(gè)代碼就是因?yàn)殚]包的問(wèn)題,導(dǎo)致錯(cuò)誤。又如:

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)境的全局性

解決這個(gè)問(wè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"]

再舉個(gè)例子:

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 的值可能會(huì)發(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 與上面的是相同的,多了個(gè)括號(hào)而已
console.log((obj.getName = obj.getName)()); //the window

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

內(nèi)存泄露

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

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/78219.html

相關(guān)文章

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

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

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

    摘要:?jiǎn)误w內(nèi)置對(duì)象單體內(nèi)置對(duì)象就是開(kāi)發(fā)人員不必顯式地實(shí)例化內(nèi)置對(duì)象,因?yàn)樗麄円呀?jīng)實(shí)例化了。前面的章節(jié)討論過(guò)了大多數(shù)內(nèi)置對(duì)象,還定義了兩個(gè)單體內(nèi)置對(duì)象和。 單體內(nèi)置對(duì)象 單體內(nèi)置對(duì)象就是開(kāi)發(fā)人員不必顯式地實(shí)例化內(nèi)置對(duì)象,因?yàn)樗麄円呀?jīng)實(shí)例化了。前面的章節(jié)討論過(guò)了大多數(shù)內(nèi)置對(duì)象,ECMA-262 還定義了兩個(gè)單體內(nèi)置對(duì)象:Global 和Math。 Global 對(duì)象 所有在全局作用域中定義的屬性...

    xushaojieaaa 評(píng)論0 收藏0
  • JavaScript引用類型——“Function類型”注意要點(diǎn)

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

    fantix 評(píng)論0 收藏0
  • JavaScript引用類型——“RegExp類型”注意要點(diǎn)

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

    mochixuan 評(píng)論0 收藏0
  • 深入理解javascript原型閉包

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

    jemygraw 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<