JavaScript學(xué)習(xí)筆記整理(6):函數(shù)

2018-06-19 12:00 更新
       函數(shù)就是一段可以反復(fù)調(diào)用的代碼塊。

函數(shù)使用function關(guān)鍵字來(lái)定義,還包括一個(gè)稱(chēng)為形參(parameter)的標(biāo)識(shí)符列表,這些參數(shù)在函數(shù)體內(nèi)像局部變量一樣工作。

函數(shù)調(diào)用會(huì)為形參提供實(shí)參的值。函數(shù)使用它們實(shí)參的值來(lái)計(jì)算返回值,稱(chēng)為該函數(shù)調(diào)用表達(dá)式的值。

除了實(shí)參之外,每次調(diào)用還會(huì)擁有另一個(gè)值---本次調(diào)用的上下文---這就是this關(guān)鍵字的值。

如果函數(shù)掛載在一個(gè)對(duì)象上,作為對(duì)象的一個(gè)屬性,就稱(chēng)它為對(duì)象的方法。

JavaScript的函數(shù)可以嵌套在其他函數(shù)中定義,這樣它們就可以訪問(wèn)它們被定義時(shí)所處的作用域中的任何變量,這就是JavaScript的閉包。 1、函數(shù)定義(聲明)

JavaScript有三種方法,可以定義一個(gè)函數(shù)。

(1)function命令

function name() {}

name是函數(shù)名稱(chēng)標(biāo)識(shí)符。函數(shù)名稱(chēng)是函數(shù)聲明語(yǔ)句必需的部分。不過(guò)對(duì)于函數(shù)表達(dá)式來(lái)說(shuō),名稱(chēng)是可選的:如果存在,該名字只存在于函數(shù)體內(nèi),并指向該函數(shù)對(duì)象本身。 圓括號(hào):圓括號(hào)內(nèi)可放置0個(gè)或多個(gè)用逗號(hào)隔開(kāi)的標(biāo)識(shí)符組成的列表,這些標(biāo)識(shí)符就是函數(shù)的參數(shù)名稱(chēng)。 花括號(hào):可包含0條或多條JavaScript語(yǔ)句。這些語(yǔ)句構(gòu)成了函數(shù)體。一旦調(diào)用函數(shù),就會(huì)執(zhí)行這些語(yǔ)句。 (2)函數(shù)表達(dá)式

var f = function(x){   

  console.log(x);  

}

采用函數(shù)表達(dá)式聲明函數(shù)時(shí),function命令后面不帶有函數(shù)名。如果加上函數(shù)名,該函數(shù)名只在函數(shù)體內(nèi)部有效,在函數(shù)體外部無(wú)效。
(3)Function()
函數(shù)定義還可以通過(guò)Function()構(gòu)造函數(shù)來(lái)定義

var f=new Function('x','y','return x+y');

等價(jià)于

var f=function(x,y){

  return x+y;

}

除了最后一個(gè)參數(shù)是函數(shù)體外,前面的其他參數(shù)都是函數(shù)的形參。如果函數(shù)不包含任何參數(shù),只須給構(gòu)造函數(shù)簡(jiǎn)單的傳入一個(gè)字符串---函數(shù)體---即可。 不過(guò),F(xiàn)unction()構(gòu)造函數(shù)在實(shí)際編程中很少會(huì)用到。

注意點(diǎn):
如果同一個(gè)函數(shù)被多次定義(聲明),后面的定義(聲明)就會(huì)覆蓋前面的定義(聲明)

function f(){

 console.log(1);

}

f()  //1


function f(){

 console.log(2);

}

f()  //2

函數(shù)可以調(diào)用自身,這就是遞歸(recursion)

function f(x){

  if(x>2){

    console.log(x);

    return f(x-1);

  }else{

    return 1;

  }

}

f(4); 

// 4

//3

不能再條件語(yǔ)句中聲明函數(shù) 2、函數(shù)命名
任何合法的JavaScript標(biāo)識(shí)符都可以用做一個(gè)函數(shù)的名稱(chēng)。函數(shù)名稱(chēng)通常是動(dòng)詞或以動(dòng)詞為前綴的詞組。 通常函數(shù)名的第一個(gè)字符為小寫(xiě)。當(dāng)函數(shù)名包含多個(gè)單詞時(shí),可采取下劃線法,比如:like_this();也可以采取駝峰法,也就是除了第一個(gè)單詞之外的單詞首字母使用大寫(xiě)字母,比如:likeThis();
3、被提前
就像變量的“被提前”一樣,函數(shù)聲明語(yǔ)句也會(huì)“被提前”到外部腳本或外部函數(shù)作用域的頂部,所以以這種方式聲明的函數(shù),可以被在它定義之前出現(xiàn)的代碼所調(diào)用。

f()


function f(){}

上面的代碼不會(huì)報(bào)錯(cuò)。
注意:以表達(dá)式定義的函數(shù)并沒(méi)有“被提前”。

f();  

var f = function (){};  

// TypeError: f is not a function

變量其實(shí)是分為聲明,賦值兩部分的,上面的代碼等同于下面的形式

var f;

f();

f = function() {};

調(diào)用f的時(shí)候,f只是被聲明了,還沒(méi)有被賦值,等于undefined,所以會(huì)報(bào)錯(cuò)。

4、嵌套函數(shù)

在JavaScript中,函數(shù)可以嵌套在其他函數(shù)里。

function go(){   

  function play(){}   

  return play();  

}

5、函數(shù)調(diào)用

構(gòu)成函數(shù)主體的JavaScript代碼在定義時(shí)并不會(huì)執(zhí)行,只有調(diào)用該函數(shù),它們才會(huì)執(zhí)行。有4種方式調(diào)用JavaScript函數(shù):
  • 作為函數(shù)
  • 作為方法
  • 作為構(gòu)造函數(shù)
  • 通過(guò)它們的call()和apply()方法間接調(diào)用

5.1函數(shù)調(diào)用

f();

5.2方法調(diào)用

o.f=funciton(){} o.f();

5.3構(gòu)造函數(shù)調(diào)用
如果函數(shù)或者方法調(diào)用之前帶有關(guān)鍵字new,它就構(gòu)成構(gòu)造函數(shù)調(diào)用。 凡是沒(méi)有形參的構(gòu)造函數(shù)調(diào)用都可以省略圓括號(hào)。

var o=new Object(); var o=new Object;

5.4間接調(diào)用
6、函數(shù)的實(shí)參和形參
可選形參 當(dāng)調(diào)用函數(shù)的時(shí)候傳入的實(shí)參比函數(shù)聲明時(shí)指定的形參個(gè)數(shù)要少,剩下的形參都將設(shè)置為undefined值。 為了保持好的適應(yīng)性,一般應(yīng)當(dāng)給參數(shù)賦予一個(gè)合理的默認(rèn)值。

function go(x,y){   

  x = x || 1;   

  y = y || 2;  

}

注意:當(dāng)用這種可選實(shí)參來(lái)實(shí)現(xiàn)函數(shù)時(shí),需要將可選實(shí)參放在實(shí)參列表的最后。那些調(diào)用你的函數(shù)的程序員是沒(méi)法省略第一個(gè)參數(shù)并傳入第二個(gè)實(shí)參的。
可變長(zhǎng)的實(shí)參列表:實(shí)參對(duì)象

當(dāng)調(diào)用函數(shù)時(shí),傳入的實(shí)參個(gè)數(shù)超過(guò)函數(shù)定義時(shí)的形參個(gè)數(shù)時(shí),是沒(méi)有辦法直接獲得未命名值的引用。

這時(shí),標(biāo)識(shí)符arguments出現(xiàn)了,其指向?qū)崊?duì)象的引用,實(shí)參對(duì)象是一個(gè)類(lèi)數(shù)組對(duì)象,可以通過(guò)數(shù)字下標(biāo)來(lái)訪問(wèn)傳入函數(shù)的實(shí)參值,而不用非要通過(guò)名字來(lái)得到實(shí)參。

function go(x){   

  console.log(arguments[0]);   

  console.log(arguments[1]);  

}  

go(1,2);  

//1

//2

arguments有一個(gè)length屬性,用以標(biāo)識(shí)其所包含元素的個(gè)數(shù)。

function f(x){

  console.log(arguments.length);

}

f(1,2)  // 2

注意:arguments并不是真正的數(shù)組,它是一個(gè)實(shí)參對(duì)象。每個(gè)實(shí)參對(duì)象都包含以數(shù)字為索引的一組元素以及l(fā)ength屬性。

通過(guò)實(shí)參名字來(lái)修改實(shí)參值的話,通過(guò)arguments[]數(shù)組也可以獲取到更改后的值。

function f(x){   

  console.log(x);    // 1

  arguments[0]=null;   

  console.log(x);    // null

}


f(1);

在上面的例子中,arguments[0]和x指代同一個(gè)值,修改其中一個(gè)的值會(huì)影響到另一個(gè)。 注意:如果有同名的參數(shù),則取最后出現(xiàn)的那個(gè)值。

function f(x,x){

 console.log(x);

}

f(1,2)  // 2

callee和caller屬性
arguments對(duì)象帶有一個(gè)callee屬性,返回它所對(duì)應(yīng)的原函數(shù)。

7、將對(duì)象屬性用做實(shí)參

當(dāng)一個(gè)函數(shù)包含超過(guò)三個(gè)形參時(shí),要記住調(diào)用函數(shù)中實(shí)參的正確順序是件讓人頭疼的事。不過(guò),我們可以通過(guò)名/值對(duì)的形式傳入?yún)?shù),這樣就無(wú)法管參數(shù)的順序了。
function f(params){ console.log(params.name); } f({name:'a'}) 8、作為值的函數(shù)
在JavaScript中,我們可以將函數(shù)賦值給變量。 function f(){} var a=f;
9、函數(shù)作用域
作用域(scope)指的是變量存在的范圍。Javascript只有兩種作用域:一種是全局作用域,變量在整個(gè)程序中一直存在,所有地方都可以讀??;另一種是函數(shù)作用域,變量只在函數(shù)內(nèi)部存在。 在函數(shù)外部聲明的變量就是全局變量(global variable),它可以在函數(shù)內(nèi)部讀取。

var a=1;

function f(){

 console.log(a)

}

f()  //1

上面的代碼中,函數(shù)f內(nèi)部可以讀取全局變量a。

在函數(shù)內(nèi)部定義的變量,外部無(wú)法讀取,稱(chēng)為“局部變量”(local variable)。

function f(){

  var a=1;

}

v  //ReferenceError: v is not defined

上面代碼中,變量v在函數(shù)內(nèi)部定義,所以是一個(gè)局部變量,函數(shù)之外就無(wú)法讀取。

函數(shù)內(nèi)部定義的變量,會(huì)在該作用域內(nèi)覆蓋同名全局變量。

var a=1;

function f(){

  var a=2;

  console.log(a);

}

f()  //2

a  //1

注意:對(duì)于var命令來(lái)說(shuō),局部變量只能在函數(shù)內(nèi)部聲明,在其他區(qū)塊中聲明,一律都是全局變量。
函數(shù)的執(zhí)行依賴(lài)于變量作用域,這個(gè)作用域是在函數(shù)定義時(shí)決定的,而不是函數(shù)調(diào)用時(shí)決定的。
10、函數(shù)內(nèi)部的變量提升
與全局作用域一樣,函數(shù)作用域內(nèi)部也會(huì)產(chǎn)生“變量提升”現(xiàn)象。var命令聲明的變量,不管在什么位置,變量聲明都會(huì)被提升到函數(shù)體的頭部。

function f(x){

  if(x>10){

    var a = x -1;

  }

}


//等同于


function f(x){

  var a;

  if(x>10){

    a = x - 1;

  }

}

11、函數(shù)屬性、方法和構(gòu)造函數(shù)
name屬性
name屬性返回緊跟在function關(guān)鍵字之后的那個(gè)函數(shù)名。

function f(){}

f.name   //f

length屬性
函數(shù)的length屬性是只讀屬性,代表函數(shù)形參的數(shù)量,也就是在函數(shù)定義時(shí)給出的形參個(gè)數(shù)。

function f(x,y){}

f.length  //2

prototype屬性 每一個(gè)函數(shù)都包含一個(gè)prototype屬性,這個(gè)屬性指向一個(gè)對(duì)象的引用,這個(gè)對(duì)象稱(chēng)做“原型對(duì)象”(prototype object)。
call()方法和apply()方法

call()

語(yǔ)法:call([thisObj[,arg1[, arg2[, [,.argN]]]]]) 定義:調(diào)用一個(gè)對(duì)象的一個(gè)方法,以另一個(gè)對(duì)象替換當(dāng)前對(duì)象。
說(shuō)明: call 方法可以用來(lái)代替另一個(gè)對(duì)象調(diào)用一個(gè)方法。call 方法可將一個(gè)函數(shù)的對(duì)象上下文從初始的上下文改變?yōu)橛?thisObj 指定的新對(duì)象。

apply()

語(yǔ)法:apply([thisObj[,argArray]]) 定義:應(yīng)用某一對(duì)象的一個(gè)方法,用另一個(gè)對(duì)象替換當(dāng)前對(duì)象。
說(shuō)明: 如果 argArray 不是一個(gè)有效的數(shù)組或者不是 arguments 對(duì)象,那么將導(dǎo)致一個(gè) TypeError。 如果沒(méi)有提供 argArray 和 thisObj 任何一個(gè)參數(shù),那么 Global 對(duì)象將被用作 thisObj, 并且無(wú)法被傳遞任何參數(shù)。 bind()方法
bind()方法是在ECMAScript 5中新增的方法。 toString()方法

函數(shù)的toString方法返回函數(shù)的源碼。

function f(){

  return 1;

}

f.toString()  

//function f(){

//  return 1;

//}

12、閉包
JavaScript的函數(shù)可以嵌套在其他函數(shù)中定義,這樣它們就可以訪問(wèn)它們被定義時(shí)所處的作用域中的任何變量,這就是JavaScript的閉包。 閉包的最大用處有兩個(gè),一個(gè)是可以讀取函數(shù)內(nèi)部的變量,另一個(gè)就是讓這些變量始終保持在內(nèi)存中,即閉包可以使得它誕生環(huán)境一直存在。

function f(a){   

  return function(){   

    return a++;   

  };   

}   

var c=f(1);   

console.log(c());    //1

console.log(c());   //2

console.log(c());  //3

閉包的另一個(gè)用處,是封裝對(duì)象的私有屬性和私有方法。

13、立即調(diào)用的函數(shù)表達(dá)式(
IIFE

在Javascript中,一對(duì)圓括號(hào)()是一種運(yùn)算符,跟在函數(shù)名之后,表示調(diào)用該函數(shù)。

(function(){  

  statement

}())

上面的函數(shù)會(huì)立即調(diào)用。

注意:上面代碼的圓括號(hào)的用法,function之前的左圓括號(hào)是必需的,因?yàn)槿绻粚?xiě)這個(gè)左圓括號(hào),JavaScript解釋器會(huì)試圖將關(guān)鍵字function解析為函數(shù)聲明語(yǔ)句。而使用圓括號(hào),JavaScript解釋器才會(huì)正確地將其解析為函數(shù)定義表達(dá)式。

當(dāng)然,下面的方法也會(huì)以表達(dá)式來(lái)處理函數(shù)定義的方法。

!function(){}();

~function(){}();

-function(){}();

+function(){}();


通常情況下,只對(duì)匿名函數(shù)使用這種“立即執(zhí)行的函數(shù)表達(dá)式”。它的目的有兩個(gè):
一是不必為函數(shù)命名,避免了污染全局變量;
二是IIFE內(nèi)部形成了一個(gè)單獨(dú)的作用域,可以封裝一些外部無(wú)法讀取的私有變量。
14、eval命令
eval命令的作用是,將字符串當(dāng)作語(yǔ)句執(zhí)行。

eval('var a=1');

a  //1

eval沒(méi)有自己的作用域,都在當(dāng)前作用域內(nèi)執(zhí)行

JavaScript規(guī)定,如果使用嚴(yán)格模式,eval內(nèi)部聲明的變量,不會(huì)影響到外部作用域。

(function(){

  'use strict';

  eval('var a=1');

  console.log(a);  //ReferenceError: a is not defined

})();



以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)