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

深入理解javascript函數(shù)參數(shù)與閉包

 更新時間:2016年12月12日 16:17:50   作者:unclekeith  
函數(shù)是javascript的一等對象,想要學(xué)好javascript,就必須深刻理解函數(shù)。本文對javascript函數(shù)參數(shù)與閉包進行詳細分析介紹。需要的朋友一起來看下吧

最近在學(xué)習(xí)javascript的函數(shù),函數(shù)是javascript的一等對象,想要學(xué)好javascript,就必須深刻理解函數(shù)。本人把學(xué)習(xí)的過程整理成文章,一是為了加深自己函數(shù)的理解,二是給讀者提供學(xué)習(xí)的途徑,避免走彎路。內(nèi)容有些多,但都是筆者對于函數(shù)的總結(jié)。

1.函數(shù)參數(shù)

  1.1:參數(shù)是什么

  1.2:參數(shù)的省略

  1.3:參數(shù)默認值

  1.4:參數(shù)傳遞方式

  1.5:同名參數(shù)

  1.6:arguments對象

2.閉包

  2.1:閉包定義

  2.2:立即調(diào)用的函數(shù)表達式(IIFE, Immediately invoked function expression)

1.函數(shù)參數(shù)

 1.1:參數(shù)是什么

 在定義一個函數(shù)時,有時候需要為函數(shù)傳遞額外的數(shù)據(jù),不同的外部數(shù)據(jù)會得到不同的結(jié)果,這種外部數(shù)據(jù)就叫做參數(shù)。

 function keith(a){
 return a+a;
 }
 console.log(keith(3)); //6

上面代碼中,給keith函數(shù)傳遞了參數(shù)a,并且返回了a+a表達式。

1.2:參數(shù)的省略

函數(shù)參數(shù)不是必須的,javascript規(guī)范允許省略調(diào)用時傳遞的實際參數(shù)。

 function keith(a, b, c) {
 return a;
 }
 console.log(keith(1, 2, 3)); //1
 console.log(keith(1)); //1
 console.log(keith()); // 'undefined'

上面代碼中,keith函數(shù)定義了三個參數(shù),但是在調(diào)用時無論傳遞了多少個參數(shù),javascript都不會報錯。被省略的參數(shù)的默認值就變?yōu)閡ndefined。了解函數(shù)定義與函數(shù)作用域 的都知道,函數(shù)的length屬性會返回參數(shù)個數(shù)。需要注意的是,length屬性與實際參數(shù)的個數(shù)無關(guān),只是返回形式參數(shù)的個數(shù)。

(實際參數(shù):調(diào)用時傳遞的參數(shù)。     形式參數(shù):定義時傳遞的參數(shù)。)

但是沒有辦法省略只靠前的元素,而保留靠后的元素。如果一定要省略靠前的元素,只有顯示傳入undefined。

 function keith(a, b) {
 return a;
 }
 console.log(keith(, 1)); //SyntaxError: expected expression, got ','
 console.log(keith(undefined, 2)); //'undefined'

上面代碼中,如果省略了第一個參數(shù),瀏覽器就會報錯。如果給第一個參數(shù)傳遞undefined,則不會報錯。

1.3:默認值

在JavaScript中,函數(shù)參數(shù)的默認值是undefined。然而,在某些情況下設(shè)置不同的默認值是有用的。一般策略是在函數(shù)的主體測試參數(shù)值是否為undefined,如果是則賦予一個值,如果不是,則返回實際參數(shù)傳遞的值。

 function keith(a, b) {
 (typeof b !== 'undefined') ? b = b: b = 1;
 return a * b;
 }
 console.log(keith(15)); //15
 console.log(keith(15, 2)) //30

上面代碼中,做了個判斷。當在調(diào)用時沒有傳入b參數(shù),則默認為1。

從ECMAScript 6開始,定義了默認參數(shù)(default parameters)。使用默認參數(shù),在函數(shù)體的檢查就不再需要了。

 function keith(a, b = 1) {
 return a * b;
 }
 console.log(keith(15)); //15
 console.log(keith(15, 2)) //30

1.4:參數(shù)傳遞方式

函數(shù)參數(shù)的傳遞方式有兩種,一個是傳值傳遞,一個是傳址傳遞。

當函數(shù)參數(shù)是原始數(shù)據(jù)類型時(字符串,數(shù)值,布爾值),參數(shù)的傳遞方式為傳值傳遞。也就是說,在函數(shù)體內(nèi)修改參數(shù)值,不會影響到函數(shù)外部。

 var a = 1;
 function keith(num) {
 num = 5;
 }
 keith(a);
 console.log(a); //1

上面代碼中,全局變量a是一個原始類型的值,傳入函數(shù)keith的方式是傳值傳遞。因此,在函數(shù)內(nèi)部,a的值是原始值的拷貝,無論怎么修改,都不會影響到原始值。

但是,如果函數(shù)參數(shù)是復(fù)合類型的值(數(shù)組、對象、其他函數(shù)),傳遞方式是傳址傳遞(pass by reference)。也就是說,傳入函數(shù)的是原始值的地址,因此在函數(shù)內(nèi)部修改參數(shù),將會影響到原始值。

 var arr = [2, 5];
 function keith(Arr) {
 Arr[0] = 3;
 }
 keith(arr);
 console.log(arr[0]); //3

上面代碼中,傳入函數(shù)keith的是參數(shù)對象arr的地址。因此,在函數(shù)內(nèi)部修改arr第一個值,會影響到原始值。

注意,如果函數(shù)內(nèi)部修改的,不是參數(shù)對象的某個屬性,而是替換掉整個參數(shù),這時不會影響到原始值。

 var arr = [2, 3, 5];
 function keith(Arr) {
 Arr = [1, 2, 3];
 }
 keith(arr);
 console.log(arr); // [2,3,5]

上面代碼中,在函數(shù)keith內(nèi)部,參數(shù)對象arr被整個替換成另一個值。這時不會影響到原始值。這是因為,形式參數(shù)(Arr)與實際參數(shù)arr存在一個賦值關(guān)系。

1.5:同名參數(shù)

如果有同名參數(shù),則取最后面出現(xiàn)的那個值,如果未提供最后一個參數(shù)的值,則取值變成undefined。

 function keith(a, a) {
 return a;
 }
 console.log(keith(1, 3)); //3
 console.log(keith(1)); //undefined

如果想訪問同名參數(shù)中的第一個參數(shù),則使用arguments對象。

 function keith(a, a) {
 return arguments[0];
 }
 console.log(keith(2));  //2

1.6 arguments對象

JavaScript 中每個函數(shù)內(nèi)都能訪問一個特別變量 arguments。這個變量維護著所有傳遞到這個函數(shù)中的參數(shù)列表。

arguments 對象包含了函數(shù)運行時的所有參數(shù),arguments[0]就是第一個參數(shù),arguments[1]就是第二個參數(shù),以此類推。這個對象只有在函數(shù)體內(nèi)部,才可以使用。

可以訪問arguments對象的length屬性,判斷函數(shù)調(diào)用時到底帶幾個參數(shù)。

 function keith(a, b, c) {
 console.log(arguments[0]); //1
 console.log(arguments[2]); //3
 console.log(arguments.length); //4
 }
 keith(1, 2, 3, 4);

arguments對象與數(shù)組的關(guān)系

arguments 對象不是一個數(shù)組(Array)。 盡管在語法上它有數(shù)組相關(guān)的屬性 length,但它不從 Array.prototype 繼承,實際上它是一個類數(shù)組對象。因此,無法對 arguments 變量使用標準的數(shù)組方法,比如 push, pop 或者 slice。但是可以使用數(shù)組中的length屬性。

通常使用如下方法把arguments對象轉(zhuǎn)換為數(shù)組。

var arr = Array.prototype.slice.call(arguments);

2.閉包

2.1:閉包定義

要理解閉包,需要先理解全局作用域和局部作用域的區(qū)別。函數(shù)內(nèi)部可以訪問全局作用域下定義的全局變量,而函數(shù)外部卻無法訪問到函數(shù)內(nèi)部定義(局部作用域)的局部變量。

var a = 1;
function keith() {
 return a;
 var b = 2;
 }
 console.log(keith()); //1
 console.log(b); //ReferenceError: b is not defined

上面代碼中,全局變量a可以在函數(shù)keith內(nèi)部訪問??墒蔷植孔兞縝卻無法在函數(shù)外部訪問。

如果需要得到函數(shù)內(nèi)部的局部變量,只有通過在函數(shù)的內(nèi)部,再定義一個函數(shù)。

 function keith(){
 var a=1;
 function rascal(){
 return a;
 }
 return rascal;
 }
 var result=keith();
 console.log(result()); //1
 function keith(){
 var a=1;
 return function(){
 return a;
 };
 }
 var result=keith();
 console.log(result()) //1

上面代碼中,兩種寫法相同,唯一的區(qū)別是內(nèi)部函數(shù)是否是匿名函數(shù)。函數(shù)rascal就在函數(shù)keith內(nèi)部,這時keith內(nèi)部的所有局部變量,對rascal都是可見的。但是反過來就不行,rascal內(nèi)部的局部變量,對keith就是不可見的。這就是JavaScript語言特有的”鏈式作用域”結(jié)構(gòu)(chain scope),子對象會一級一級地向上尋找所有父對象的變量。所以,父對象的所有變量,對子對象都是可見的,反之則不成立。函數(shù)keith的返回值就是函數(shù)rascal,由于rascal可以讀取keith的內(nèi)部變量,所以就可以在外部獲得keith的內(nèi)部變量了。

閉包就是函數(shù)rascal,即能夠讀取其他函數(shù)內(nèi)部變量的函數(shù)。由于在JavaScript語言中,只有函數(shù)內(nèi)部的子函數(shù)才能讀取內(nèi)部變量,因此可以把閉包簡單理解成“定義在一個函數(shù)內(nèi)部的函數(shù)”。閉包最大的特點,就是它可以“記住”誕生的環(huán)境,比如rascal記住了它誕生的環(huán)境keith,所以從rascal可以得到keith的內(nèi)部變量。

閉包可以使得它誕生環(huán)境一直存在??聪旅嬉粋€例子,閉包使得內(nèi)部變量記住上一次調(diào)用時的運算結(jié)果。

 function keith(num) {
 return function() {
 return num++;
 };
 }
 var result = keith(2);
 console.log(result()) //2
 console.log(result()) //3
 console.log(result()) //4

上面代碼中,參數(shù)num其實就相當于函數(shù)keith內(nèi)部定義的局部變量。通過閉包,num的狀態(tài)被保留了,每一次調(diào)用都是在上一次調(diào)用的基礎(chǔ)上進行計算。從中可以看到,閉包result使得函數(shù)keith的內(nèi)部環(huán)境,一直存在。

通過以上的例子,總結(jié)一下閉包的特點:

1:在一個函數(shù)內(nèi)部定義另外一個函數(shù),并且返回內(nèi)部函數(shù)或者立即執(zhí)行內(nèi)部函數(shù)。

2:內(nèi)部函數(shù)可以讀取外部函數(shù)定義的局部變量

3:讓局部變量始終保存在內(nèi)存中。也就是說,閉包可以使得它誕生環(huán)境一直存在。

閉包的另一個用處,是封裝對象的私有屬性和私有方法。

 function Keith(name) {
 var age;
 function setAge(n) {
 age = n;
 }
 function getAge() {
 return age;
 }
 return {
 name: name,
 setAge: setAge,
 getAge: getAge
 };
 }
 var person = Keith('keith');
 person.setAge(21);
 console.log(person.name); // 'keith'
 console.log(person.getAge()); //21

2.2:立即調(diào)用的函數(shù)表達式(IIFE)

通常情況下,只對匿名函數(shù)使用這種“立即執(zhí)行的函數(shù)表達式”。它的目的有兩個:一是不必為函數(shù)命名,避免了污染全局變量;二是IIFE內(nèi)部形成了一個單獨的作用域,可以封裝一些外部無法讀取的私有變量。

循環(huán)中的閉包

一個常見的錯誤出現(xiàn)在循環(huán)中使用閉包,假設(shè)我們需要在每次循環(huán)中調(diào)用循環(huán)序號

 for(var i=0;i<10;i++){
 setTimeout(function(){
 console.log(i); //10
 }, 1000)
 }

上面代碼中,不會符合我們的預(yù)期,輸出數(shù)字0-9。而是會輸出數(shù)字10十次。

當匿名函數(shù)被調(diào)用的時候,匿名函數(shù)保持著對全局變量 i 的引用,也就是說會記住i循環(huán)時執(zhí)行的結(jié)果。此時for循環(huán)結(jié)束,i 的值被修改成了10。

為了得到想要的效果,避免引用錯誤,我們應(yīng)該使用IIFE來在每次循環(huán)中創(chuàng)建全局變量 i 的拷貝。

for(var i = 0; i < 10; i++) {
 (function(e) {
 setTimeout(function() {
 console.log(e); //1,2,3,....,10
 }, 1000);
 })(i);
 }

外部的匿名函數(shù)會立即執(zhí)行,并把 i 作為它的參數(shù),此時函數(shù)內(nèi) e 變量就擁有了 i 的一個拷貝。當傳遞給 setTimeout 的匿名函數(shù)執(zhí)行時,它就擁有了對 e 的引用,而這個值是不會被循環(huán)改變的。

以上就是本文的全部內(nèi)容,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,同時也希望多多支持腳本之家!

相關(guān)文章

  • ArtEditor富文本編輯器增加表單提交功能

    ArtEditor富文本編輯器增加表單提交功能

    artEditor是一款基于jQuery的移動端富文本編輯器,支持插入圖片,后續(xù)完善其他功能。接下來通過本文給大家介紹ArtEditor富文本編輯器增加表單提交功能,對arteditor編輯器相關(guān)知識感興趣的朋友一起學(xué)習(xí)吧
    2016-04-04
  • 微信小程序?qū)崿F(xiàn)的一鍵撥號功能示例

    微信小程序?qū)崿F(xiàn)的一鍵撥號功能示例

    這篇文章主要介紹了微信小程序?qū)崿F(xiàn)的一鍵撥號功能,結(jié)合實例形式分析了微信小程序使用wx.makePhoneCall實現(xiàn)撥打電話功能相關(guān)操作技巧,需要的朋友可以參考下
    2019-04-04
  • 基于three.js編寫的一個項目類示例代碼

    基于three.js編寫的一個項目類示例代碼

    這篇文章主要給大家介紹了關(guān)于基于three.js編寫的一個項目類的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2018-01-01
  • D3.js中data(), enter() 和 exit()的問題詳解

    D3.js中data(), enter() 和 exit()的問題詳解

    相信大多數(shù)人對D3.js并不陌生。這是一個由紐約時報可視化編輯 Mike Bostock與他斯坦福的教授和同學(xué)合作開發(fā)的數(shù)據(jù)文件處理的JavaScript Library,全稱叫做Data-Driven Documents,在d3.js中data(), enter() 和 exit()比較常見,下面給大家就這方面的知識給大家詳解
    2015-08-08
  • Bootstrap?按鈕下拉菜單的實現(xiàn)示例

    Bootstrap?按鈕下拉菜單的實現(xiàn)示例

    本文主要介紹了Bootstrap?按鈕下拉菜單的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • 一個簡單的JS鼠標懸停特效具體方法

    一個簡單的JS鼠標懸停特效具體方法

    這個特效最終實現(xiàn)效果就是當鼠標移動到鏈接上,文字會橫向移動一定距離,貌似總有人喜歡這些花花草草。添加此效果方法很簡單。
    2013-06-06
  • JS實現(xiàn)電影票選座的項目示例

    JS實現(xiàn)電影票選座的項目示例

    電影院選座基本上每個人都用到過,本文主要介紹了JS實現(xiàn)電影票選座的項目示例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • 表格 隔行換色升級版

    表格 隔行換色升級版

    表格隔行換色升級版,直接用javascript實現(xiàn)。
    2009-11-11
  • JavaScript利用append添加元素報錯的解決方法

    JavaScript利用append添加元素報錯的解決方法

    這篇文章主要介紹了JavaScript利用append添加元素報錯的解決方法,需要的朋友可以參考下
    2014-07-07
  • JS實現(xiàn)slide文字框縮放伸展效果代碼

    JS實現(xiàn)slide文字框縮放伸展效果代碼

    這篇文章主要介紹了JS實現(xiàn)slide文字框縮放伸展效果代碼,涉及JavaScript響應(yīng)鼠標事件動態(tài)操作頁面元素屬性的相關(guān)技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-11-11

最新評論