欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JavaScript必知必會(九)function 說起 閉包問題

 更新時間:2016年06月08日 12:00:19   作者:Company  
這篇文章主要介紹了JavaScript必知必會(九)function 說起 閉包問題的相關(guān)資料,需要的朋友可以參考下

function

函數(shù)格式

function getPrototyNames(o,/*optional*/ a)
{
a = a || [];
for(var p in o)
{
a.push(p);
}
return a;
} 

caller

func.caller 返回函數(shù)調(diào)用者

function callfunc()
{
if(callfunc.caller)
{
alert(callfunc.caller.toString());
}else
{
alert("沒有函數(shù)調(diào)用");
}
}
function handleCaller()
{
callfunc();
}
handleCaller();//返回 handler
callfunc();//沒有函數(shù)調(diào)用,返回null,執(zhí)行了《沒有函數(shù)調(diào)用》 

callee

匿名方法遞歸調(diào)用

alert( (function (x) {
if (x <= ) return ;
return x * arguments.callee(x - );
}()));// 

scope

作用域大家都不陌生,今天就來說說閉包問題,深刻吃透閉包問題。

<script>
var global = "global scope";//這個是全局的作用域
function scope()
{
var scope = "local scope";//這個是局部的作用域
return scope;//返回的scope,是局部的變量
}
</script> 

  1、:定義的全局變量也能在函數(shù)內(nèi)部訪問。當(dāng)定義的局部變量和全局變量名字相同時,局部變量的就會隱藏全局變量,不會破壞全局變量的值。

var scope = "global scope";
function f()
{
var scope = "local scope";
return scope;
}
alert(f());//local scope
alert(scope);//global scope; 

  上面確實是很容易理解,對吧。

2、 全局變量可以不用var聲明,但是局部變量必須使用var聲明,如果局部變量不使用var聲明,編譯器會默認(rèn)這個是個全局變量。

<span style="line-height: .; font-family: verdana, Arial, Helvetica, sans-serif; font-size: px; background-color: rgb(, , );">  </span> 
scope = "global scope";
function f()
{
scope = "local scope";
return scope;
}
alert(f());//local scope
alert(scope);//local scope

  但是全局變量不使用var聲明,也僅限非嚴(yán)格模式,如果使用嚴(yán)格模式的話,會報錯誤

<script>
"use strict";
scope = "global scope";
function f()
{
scope = "local scope";
return scope;
}
alert(f());//local scope
alert(scope);//local scope
</script>

所以建議大家聲明變量時,千萬不要省略var,可以避免不必要的麻煩。

3、 聲明提前,也是可以滴。什么叫什么提前。

<script>
"use strict";
scope;
console.log(scope);
var scope = "global scope";
console.log(scope);
</script> 

這個可能大家看出第一個打印undefined ,是呀還沒有給他賦值, 下面賦值可定打印global scope了。

這樣理解并沒有錯,但是為什么會這樣的呢,一個變量不是應(yīng)該先定義才可以使用的嗎?

這里給大家說下作用域鏈,JavaScript是基于詞法作用域的語言。

1、作用域鏈?zhǔn)且粋€對象或者鏈表,這組代碼中定義了這段代碼"作用域中“的變量。當(dāng)JavaScript需要查找變量scope時,就會從鏈中的第一個對象開發(fā)查找,如果第一個對象為scope,則會直接返回這個對象的值,如果不存在繼續(xù)第二對象開始查找,直到找到。如果在作用域鏈上未查到該變量,則會拋出一個錯誤。

我們可以這個作用鏈可以這樣表示:查找 scope->window(全局對象)很顯然后面是有定義scope的。但是并沒有做賦值操作,后面才做賦值操作,所以此時值為undefined.

4、這個比較具有迷惑性了,大家猜想下打印的值是什么?

<script>
"use strict";
var scope = "global scope";
function f() {
console.log(scope);
var scope = "local scope";
console.log(scope);
}
f();
</script>

看到這段代碼:如果你粗心大意的話,很有可能會寫出錯誤的答案:

1、gobal scope

2、local scope

分析: 聲明了全局變量,在函數(shù)體中時,第一個表示全局變量,所以打印global,第二定義了局部的變量,覆蓋掉了全局的scope,所以打印local scope。

這樣的分析在C# java ,完全正確。但是這里分析確實錯誤的。

這說明這個問題前,我們先看一個問題。

這句話很重要:全局變量在程序中始終都是有定義的。局部變量在聲明它的函數(shù)體以及其所嵌套的函數(shù)內(nèi)始終是定義的。

如果你是從事高級語言工作開始接觸JavaScript 有點不適應(yīng)其作用域的定義。我也是這樣的。我們來看一個例子:

<script>
var g = "global scope";
function f()
{
for(var i=;i<;i++)
{
for(var j=;j<;j++)
{
;
}
console.log(j);
}
console.log(i);
}
console.log(g);
f();
</script>

  打印的結(jié)果是什么?

大家看到{} 表示語句塊,語句塊在一塊作用域,所以大家可能猜想,j、i值已經(jīng)在內(nèi)存釋放掉了,所以結(jié)果肯定是undefined.

真實的結(jié)果可能令你失望,

結(jié)果為什么會是這樣,我開始的表情和你一樣。

這時查看我讓你記住的那句話。。。全局變量在程序中始終都是有定義的。局部變量在聲明它的函數(shù)體以及其所嵌套的函數(shù)內(nèi)始終是定義的。

確切的說函數(shù)的參數(shù) 也是屬于局部變量的范疇。這句話也很重要?。?!

那句話大概意思說,只要是在函數(shù)內(nèi)部定義的變量,在整個函數(shù)內(nèi)都是有效的。所以結(jié)果也就不難理解了。在回過頭看我們的那個問題,你理解了嗎?

作用鏈還有以下定義:

1、作用鏈?zhǔn)怯幸粋€全局對象組成。

2、在不包含嵌套的函數(shù)體內(nèi),作用鏈上有兩個對象,第一個定義了函數(shù)參數(shù)和局部變量的對象,第二個是全局對象。

3、在一個嵌套的函數(shù)體內(nèi),作用鏈上至少包含三個對象。

當(dāng)定以一個函數(shù)的時候,就會保存一個作用域鏈。

當(dāng)調(diào)用這個函數(shù)時,它就會創(chuàng)建一個新的對象來存儲它的局部變量,并將這個對象添加到保存的作用鏈上。同時創(chuàng)建一個新的更長的表示函數(shù)調(diào)用的作用鏈。

對于嵌套的函數(shù),當(dāng)調(diào)用外部函數(shù)時,內(nèi)部函數(shù)又會重新定義一遍。因為每次調(diào)用外部函數(shù)的時候,作用鏈都是不同的。內(nèi)部函數(shù)在每次定義的時候都有微妙的差別,每次調(diào)用的外部函數(shù)時,內(nèi)部函數(shù)的代碼都是相同的,而且關(guān)聯(lián)的代碼的作用域也是不同的。

閉包

搞了這么久終于要講了,但是再將之前我們在來分析下作用域。

<script>
var nameg="global"
var g = function f() {
console.log(name);
function demo()
{
console.log("demo="+name);
}
var name = "";
function demo() {
var name = "";
console.log("demo=" + name);
}
function demo() {
console.log("demo=" + nameg);
}
demo();
demo();
demo();
};
g();
</script>

  我們按照作用鏈來分析:

調(diào)用demo0, demo0()->查找name,未找到->f()查找,返回

調(diào)用demo1,demo1()->查找name,找到,返回

調(diào)用demo2,demo2()->查找nameg,未找到->f()查找nameg,未找到->window查找nameg找到,返回。

看這個例子:

<script>
function f()
{
var count = ;
return { counter:function() {
return count++;
},reset:
function()
{
return count = ;
}
}
}
var d = f();
var c = f();
console.log("d第一次調(diào)用:"+ d.counter());//
console.log("c第一次調(diào)用:"+ c.counter());// 互不影響
console.log("d第一次調(diào)用:"+ d.reset());//
console.log("c第二次調(diào)調(diào)用"+ c.counter());//
</script>

  這個例子上大家可以看到,我做了一個計數(shù)和置零的操作。

創(chuàng)建了兩個f的對象實例d c,各有自己的作用域鏈,所以其值互不影響。當(dāng)c第二次調(diào)用時,count值被保存了,因為c對象并未被銷毀。明白這個例子后,后面的例子才比較好懂。

這個過程,大家應(yīng)該十分明了了。那么現(xiàn)在我們來看閉包問題。我設(shè)置四個按鈕,點擊每個按鈕就返回響應(yīng)的名字。

<body>
<script>
function btnInit()
{
for(var i=;i<;i++)
{
var btn = document.getElementById("btn" + i);
btn.addEventListener("click",function() {
alert("btn" + i);
});
}
}
window.onload= btnInit;
</script>
<div>
<button id="btn">Btn</button>
<button id="btn">Btn</button>
<button id="btn">Btn</button>
<button id="btn">Btn</button>
</div>
</body>

  點擊運行,結(jié)果卻是都是btn5;

我們用剛才的分析在坐下,首先要調(diào)用匿名函數(shù)->查找i,未找到->btnInit(),找到i在for循環(huán)中。找到。我們知道只有函數(shù)調(diào)用結(jié)束才釋放,for中的i總是可見的,所以保留了最后的i值。那么如何解決呢。

解決i值在函數(shù)中不是總是可見的,那么我們就要使用函數(shù)的嵌套了,然后把i值傳進去。

function btnInit()
{
for(var i=;i<;i++)
{
(function (data_i) {
var btn = document.getElementById("btn" + data_i);
btn.addEventListener("click", function () {
alert("btn" + data_i);
});
}(i));
}
}

  看修改后的代碼,首先執(zhí)行第一次for,創(chuàng)建了一個對象,我們首先是執(zhí)行匿名函數(shù)->data_i,未找到->function(data_i)找到,然后再次執(zhí)行for有創(chuàng)建一個對象,閉包規(guī)則說的互不影響。所以能得出正確的結(jié)果。

以上所述是小編給大家介紹的 JavaScript必知必會(九)function 說起 閉包問題的相關(guān)知識,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!

相關(guān)文章

  • form表單中去掉默認(rèn)的enter鍵提交并綁定js方法實現(xiàn)代碼

    form表單中去掉默認(rèn)的enter鍵提交并綁定js方法實現(xiàn)代碼

    form表單中默認(rèn)的enter提交是不是讓你已經(jīng)很耐煩了吧,本文主要講解一下如何去掉默認(rèn)的enter鍵提交同時綁定js方法,感興趣的朋友可以參考下哈
    2013-04-04
  • js樹插件zTree獲取所有選中節(jié)點數(shù)據(jù)的方法

    js樹插件zTree獲取所有選中節(jié)點數(shù)據(jù)的方法

    這篇文章主要介紹了js樹插件zTree獲取所有選中節(jié)點數(shù)據(jù)的方法,是對js樹插件zTree非常實用的操作,需要的朋友可以參考下
    2015-01-01
  • Jquery 常用方法一覽表(集合)

    Jquery 常用方法一覽表(集合)

    之前腳本之家發(fā)過相關(guān)的文章,這里又是一篇關(guān)于jquery常用方法的收集整理,我們給放到一起,學(xué)習(xí)jquery的朋友可以參考下。
    2010-03-03
  • 原生js實現(xiàn)下拉菜單

    原生js實現(xiàn)下拉菜單

    這篇文章主要為大家詳細介紹了原生js實現(xiàn)下拉菜單,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • 異步j(luò)avascript的原理和實現(xiàn)技巧介紹

    異步j(luò)avascript的原理和實現(xiàn)技巧介紹

    因為工作的需要,我要在網(wǎng)頁端編寫一段腳本,把數(shù)據(jù)通過網(wǎng)頁批量提交到系統(tǒng)中去。所以我就想到了Greasemonkey插件,于是就開始動手寫,發(fā)現(xiàn)問題解決得很順利
    2012-11-11
  • JavaScript數(shù)組基于交換的排序示例【冒泡排序】

    JavaScript數(shù)組基于交換的排序示例【冒泡排序】

    這篇文章主要介紹了JavaScript數(shù)組基于交換的排序,結(jié)合實例形式分析了JavaScript排序算法中的冒泡排序簡單實現(xiàn)技巧,需要的朋友可以參考下
    2018-07-07
  • 關(guān)于moment.js的常用方法及使用說明

    關(guān)于moment.js的常用方法及使用說明

    這篇文章主要介紹了關(guān)于moment.js的常用方法及說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • TypeScript 裝飾器定義

    TypeScript 裝飾器定義

    這篇文章主要介紹了TypeScript 裝飾器定義,裝飾器是一種新的聲明,它可以作用于類聲明 、方法 、訪問器 、屬性以及參數(shù)上,下面我們就來看看TypeScript 裝飾器的具體定義吧,需要的朋友可以參考一下,希望對你有所幫助
    2021-12-12
  • JavaScript重復(fù)元素處理方法分析【統(tǒng)計個數(shù)、計算、去重復(fù)等】

    JavaScript重復(fù)元素處理方法分析【統(tǒng)計個數(shù)、計算、去重復(fù)等】

    這篇文章主要介紹了JavaScript重復(fù)元素處理方法,結(jié)合實例形式分析了javascript針對字符串、數(shù)組中重復(fù)元素的個數(shù)統(tǒng)計,計算及去重復(fù)等相關(guān)操作技巧,需要的朋友可以參考下
    2017-12-12
  • TypeScript數(shù)組的定義與使用詳解

    TypeScript數(shù)組的定義與使用詳解

    數(shù)組對象是使用單獨的變量名來存儲一系列的值,數(shù)組非常常用,數(shù)組是具有連續(xù)存儲位置的相似類型元素的同質(zhì)集合。數(shù)組是用戶定義的數(shù)據(jù)類型。數(shù)組是一種數(shù)據(jù)結(jié)構(gòu),我們在其中存儲相似數(shù)據(jù)類型的元素
    2022-09-09

最新評論