JavaScript函數(shù)


layout: post
title: JavaScript函數(shù)
tags: [JavaScript, 函數(shù)]
author: 楊比軒


函數(shù)定義和調用

簡單的函數(shù)定義

//求絕對值
function abs(x){
    if(x < 0)
      return -x;
    else
    return x;
}

和java語法類似:

  • function 函數(shù)關鍵字申明
  • abs 函數(shù)名
  • (x) 參數(shù)
  • {....}函數(shù)體

JS如果沒有return語句袜漩,函數(shù)執(zhí)行完畢會返回undefined

本著萬物皆對象的原則玷氏,function也是對象统求,所以:

var abs = function(x){
  ....
};

此時函數(shù)是一個匿名函數(shù)仪芒,變量abs指向匿名函數(shù)爷恳,本質上和上面那種方式沒有區(qū)別尔邓,但是這里有一點要注意付秕,此處其實是一個賦值語句兰珍,所以末尾要加上;

函數(shù)的調用

正常調用不做贅述,說說比較特殊的地方询吴。

JS函數(shù)允許傳遞多個參數(shù)或者不傳遞參數(shù)掠河,所以:

abs(1,2,“123”,4,5);//后面的參數(shù)不會生效,結果返回 1
abs(); //結果返回 NaN

返回NaN解釋:函數(shù)傳遞的x變成undefined汰寓,計算結果變成NaN

所以口柳,為了避免這種情況的產生,可以做健壯性處理:

function abs(x){
  if(x !== 'number'){
    throw 'not a number';
  }
  
  if(x > 0)
    return -x;
  else
    return x;
}

arguments

JS的函數(shù)默認會有一個arguments參數(shù)有滑,此參數(shù)指向函數(shù)的參數(shù)集跃闹,有點類似于array,但是不是array毛好。

可以使用arguments的length屬性望艺,來判斷參數(shù)的個數(shù)和對參數(shù)進行訪問

demo:

function getSum(x,y,z){
    var num = 0;
    console.log("arguments length:" + arguments.callee);
    for(var i = 0 ; i < arguments.length ; i++){
        console.log(arguments[i]);
        num = num + arguments[i];
    }
    return num;
}
console.log(getSum(1,2,3,4,5,6,7,8,9,10));
//輸出:1,2,3,4,5,6,7,8,9,10,55

rest

ES6引入的新標準肌访,用于處理多余傳入函數(shù)內的參數(shù)找默,用法:

function restDemo(x, y, ...rest){
    console.log("x="+x);
    console.log("y="+y);
    console.log("rest=" + rest);
}
restDemo(1,2,3,4,5,6);
//輸出:
//x=1
//y=2
//rest=3,4,5,6

關于return

JS有自動在行末加;的機制,所以要小心return語句

demo:

//return了一個匿名對象吼驶,這種是常規(guī)情況惩激,可以正常運行
function returnDemo(){
    return {name:'luke'};
}

//return的代碼過長時,需要換行蟹演,此時js會自動加`;`在行末风钻,所以返回undefined
function returnDemo(){
    return
    { name:'luke'};
}

//這種的也正常,{ 表示此行未結束酒请,會阻斷添加 ; 
function returnDemo(){ 
    return {
      name:'luke'
    };
}

變量的作用域

JS的函數(shù)可以嵌套骡技,所有當兩個嵌套的函數(shù)的變量重名后,內部可以調用外部變量羞反,外部則不能訪問內部布朦。

'use strict';

function foo() {
    var x = 1;
    function bar() {
        var y = x + 1; // bar可以訪問foo的變量x!
    }
    var z = y + 1; // ReferenceError! foo不可以訪問bar的變量y!

此時如果兩個參數(shù)名字相同,則內部參數(shù)相當于重寫了外部參數(shù)昼窗,會達到屏蔽的效果是趴。

'use strict';

function foo() {
    var x = 1;
    function bar() {
        var x = 'A';
        console.log('x in bar() = ' + x); // 'A'
    }
    console.log('x in foo() = ' + x); // 1
    bar();
}

變量的自動提升

在JS中可以引用稍后申明的變量而不會引發(fā)異常就是因為有自動變量提升(variable hoisting),但是提升也會帶來一些問題膏秫。

console.log(x === undefined);//logs true
var x = 3;

//上述代碼相當于
var x;
console.log(x === undefined);
x = 3;

分析:

var x = 3;相當于一個申明變量語句和一個賦值語句右遭,但是自動提升只會提升申明語句var x;僅此而已做盅。所以log輸出就是true

所以,一段代碼或者函數(shù)中的var語句應該盡可能的放在接近代碼段的頂部位置,一避免產生麻煩窘哈。

全局變量

全局變量相當于全局對象的屬性吹榴,在網頁中全局對象是window,所以可是使用window.variable來訪問和設置全局變量滚婉。
所以在函數(shù)體之用var或者const申明的變量既是全局變量图筹,也是window對象的屬性,让腹。
無論是function還是var聲明的變量远剩,在js中都是變量,也就是window的屬性骇窍,當前前提是function和var都全局的瓜晤。

局部變量
for或者if中聲明的變量其實在{}也可以引用,因為js的變量作用域其實是函數(shù)內部腹纳,而for等不是函數(shù)痢掠。
ES6引入了新標準,let關鍵字可以替代var可以申明塊級的作用域的變量嘲恍。

{
    let abc = "qweqweqweqweqweqweq";
}
console.log(abc);//logs:Uncaught ReferenceError: abc is not defined(…)

常量
ES6添加的新特性足画,const關鍵字申明一個固定值的常量。

命名空間
javascript實際上只有一個全局作用域佃牛。任何變量如果在當前函數(shù)作用域中找到淹辞,就會繼續(xù)往上找(上指的是父類),最后再全局作用中也沒有找到俘侠,就匯報ReferenceError錯誤象缀。

全局變量會綁定到window上,不同的js文件如果使用了相同的全局變量爷速,就會造成明明沖突攻冷,并且難以發(fā)現(xiàn)。

避免這個問題的方法就是把所有的變量和函數(shù)全部綁定到一個全局變量中遍希,如:

//全局變量
var MMP = {};

//其它變量
MMP.a='a';
MMP.b = function(){
    console.log("this is function");
}

這樣就可以將需要的變量申明在MMP下。

對象方法

在對象內部定義的函數(shù)也叫方法里烦,和普通的函數(shù)其實沒啥區(qū)別凿蒜,但是此種方法可以使用this關鍵字來指向當前調用方法的對象。

var person = {
    name:"bixuan",
    age:23
    //此方法就是返回對象的age屬性的value
    getAge:function(){

        return this.age;
    }
}

如果此時getAge()方法寫在person對象之外時胁黑,當person.getAge()種調用時废封,可以獲得和上面一樣的結果,但是要是單獨的調用getAge()

var person = {
    name:"bixuan",
    age:23,
    getage:getAge
}
function getAge(){
    return this.age;
}

person.getage();// 結果就是23
getAge();//結果是 undefined

person.getage指向的就是函數(shù)getAge()丧蘸,函數(shù)中的this指向的就是person對象漂洋,所以返回的就是23,而直接運行getAge()this指向的是window對象,因為沒有age屬性刽漂,所以結果是undefined演训。

還有一種情況就是函數(shù)的多層嵌套,也會導致this的調用出現(xiàn)問題贝咙。

var person = {
    name:"bixuan",
    age:23,
    
    getage:function(){

        function getAge(){
            return this.age;
        }
    }
}

person.getage();//結果是 undefined

原因就是this又重新指向了undefined了样悟,當然如果處于非strict模式下,thi又會指向window庭猩。為了避免這種情況的發(fā)生窟她,可以在外層加上一句:

...
var that = this; //用that來存儲this變量,供內層調用
function getAge(){
    return that.age;
}
...

apply()

函數(shù)對象都會有一個apply()方法蔼水,此方法接收兩個參數(shù)震糖,一個是需要綁定的this對象,第二個參數(shù)是一個Array,存儲的是函數(shù)本來的參數(shù)趴腋。

function sum(x, y){
    console.log(this.age);
    console.log( x + y);
}

sum.apply({age:23},[1,2]);
//輸出 23,3

call()和apply類似吊说,不同的是call第二個參數(shù)不是array,而是按順序將原函數(shù)所有的參數(shù)順序傳入于样。`call({},參數(shù)1,參數(shù)2,...)

利用apply的這個特性疏叨,可以用來實現(xiàn)裝飾器。

裝飾器:對已有的函數(shù)方法進行裝飾穿剖,在實現(xiàn)原有功能的基礎上蚤蔓,添加額外的功能,或者增強原有功能糊余。

function pri(){
    console.log("this is a demo");
}

var count = 0;
(function newPro(){
    count++;

    pri.apply(null,[]);
    
})();

上述例子就實現(xiàn)了對函數(shù)pri的裝飾秀又,在執(zhí)行原有代碼的同時,對其運行的次數(shù)進行了統(tǒng)計贬芥。

高階函數(shù)

普通函數(shù)接受的參數(shù)都是數(shù)據(jù)類型吐辙,高階函數(shù)就是把函數(shù)對象當作參數(shù)進行傳遞。

function sum(x, y){
    return x + y;
}

function useSum(x, y, sum){

    return sum(x, y);
}
  1. map/reduce

map()方法相當于對arr中的數(shù)據(jù)按照傳入的參數(shù)函數(shù)進行一次迭代蘸劈。

function pow(x){
    return x*x;
}

var arr = [1, 2, 3, 4, 5];

arr.map(pow);// [1,2,9,16,25]

reduce()其實也是對arr中的數(shù)據(jù)進行迭代昏苏,但是和map不同的是,reduce()相當于嵌套迭代威沫。

需要注意的是:reduce()必須接收兩個參數(shù)的函數(shù)

function sum(x, y){
    return x + y;
}

var arr = [1, 2, 3, 4, 5];

arr.reduce(sum);//15

**2. filter **

不知道官方的叫法是什么贤惯,應該翻譯做過濾器吧。使用arr調用棒掠,并傳入返回true/false來對arr中的元素進行判定從而進行過濾孵构。

var arr = [1,2,3,4,5];
var newArr = arr.filter(function(x){
    if(x%2 === 0){
        return true;
    }else{
        return false;
    }
})

console.log(arr);//[1,2,3,4,5]
console.log(newArr);//[2,4]

filter()不會更改調用數(shù)組的值,而是返回一個新的arr對象烟很。

回調函數(shù)

filter接受回調函數(shù)颈墅。

  • 當回調函數(shù)一個參數(shù)時蜡镶,代表數(shù)組的元素
  • 當對調函數(shù)三個參數(shù)時,分別為:數(shù)組的元素恤筛,元素索引官还,數(shù)組本身
arr.filter(function(a,b,c){
    console.log(a);
    console.log(b);
    console.log(c);
})

所以可以利用filter來實現(xiàn)對arr的去重復,去空元素等等操作叹俏。

//去掉arr中的重復元素
//這里利用的就是indexOf返回的是數(shù)組中該元素第一次出現(xiàn)的索引
//來實現(xiàn)對arr的去重讀
var strs = ['a','b','c','d','e','b','c','e','g','a'];

var newStrs = strs.filter(function(element, index, arr){
    if(arr.indexOf(element) == index){
        return true;
    }
    else{
        return false;
    }
})

console.log(newStrs);

3.sort

sort應該可以翻譯為排序器吧妻枕,類似java中的comparable,只需要傳入一個排序的方法,就能對調用的數(shù)組進行排序粘驰。

sort默認是將數(shù)組的元素轉換為String對象后進行排序屡谐,排序的依據(jù)是ASCII值的大小。

//按從小到大的循序排序
var nums = [12312,345345,24654356,234234,2342,4564,2342,6786,34,85,24558,62,48,4,512,5,95623];

console.log(nums.sort(function(x,y){
    if(x > y){
        return 1;
    }else{
        return -1;
    }
    return 0;
}))

通過傳入的比較方法的不同蝌数,可實現(xiàn)不同的實現(xiàn)效果愕掏,所以重點在于傳入的比較函數(shù)。

閉包

一般的方法和函數(shù)都是返回計算的結果顶伞,也就是基本數(shù)據(jù)類型和對象饵撑。當函數(shù)返回的是包含參數(shù)的函數(shù)對象時,這種的就稱為閉包唆貌。

var nums = [12312,345345,24654356,234234,2342,4564,2342,6786,34,85,24558,62,48,4,512,5,95623];
function lazy_sum(arr){
    var sum = function(){
        return arr.reduce(function(x,y){
            return x + y;
        })
    }
    return sum;
}

var result = lazy_sum(nums);

console.log(result);//[Function: sum]
console.log(result());//25383212

打印結果說明滑潘,result此時是一個函數(shù),調用此函數(shù)锨咙,輸出結果為sum()函數(shù)執(zhí)行的結果语卤。
若此時繼續(xù)執(zhí)行代碼:

nums.push(123123);
console.log(result());//25506335

但需要注意的是,此時因為傳入的引用數(shù)據(jù)類型酪刀,所以當此數(shù)據(jù)的值發(fā)生變化時粹舵,最終的結果也會受到影響。

箭頭函數(shù)

箭頭函數(shù)有點類似于java 8中的新特性骂倘。


var f = x => x+1;
//和下面的寫法實現(xiàn)了相同的功能

var f = function(x){
    return x+1;`
}

此處由于函數(shù)體比較簡單眼滤,所以省略了{...} return,并且當參數(shù)不止一個時历涝,也需要使用(...)括起來诅需。所以,箭頭函數(shù)也有以下幾種寫法:

(x,y) => x + y; //多個參數(shù)需要用括號括起來
(x,y) => {  //實現(xiàn)復復雜邏輯體時荧库,需要使用{}括起來
    if(x > y)
        return true;
    else
        return false;
}

/*空參也需要括號诱担。像這種直接返回對象的時候,需要使用()把括號
把對象括起來电爹,否則引起函數(shù)體和對象體的語法沖突而報錯
*/
() => ({name:"bixuan"}) 。

箭頭函數(shù)同時也修復了this的歷史遺留問題料睛,不是在多層調用時指向window或者undefined了丐箩,而是指向詞法作用域摇邦,也就是外層調用這的OBJ。

//以前的寫法會出現(xiàn)undefined或者指向的了window
var obj = {
    birth: 1990,
    getAge: function () {
        var b = this.birth; // 1990
        var fn = function () {
            return new Date().getFullYear() - this.birth; // this指向window或undefined
        };
        return fn();
    }
};

//而箭頭函數(shù)則不會有這個問題出現(xiàn)
var obj = {
    birth: 1990,
    getAge: function () {
        var b = this.birth; // 1990
        var fn = () => new Date().getFullYear() - this.birth; // this指向obj對象
        return fn();
    }
};
obj.getAge(); // 25

但是有一點也需要注意屎勘,就是箭頭函數(shù)因為綁定了this,所以再調用調用call()或者apply()的時候施籍,傳入的第一個參數(shù)無法對this進行綁定,還是會和上面一樣概漱,綁定在外層調用者上丑慎,所以call({...},X,Y)的第一個對象參數(shù)會被忽略掉。

var obj = {
    birth: 1990,
    getAge: function(year){
        var b = this.birth;//1990
        var fn = (y) => y - this.birth;//此時瓤摧,this.birth還是1990

        return fn.call({birth:3000},year);
    }
};
var obj2 = {
    birth: 1990,
    getAge: function(year){
        var b = this.birth;//1990
        // var fn = (y) => y - this.birth;//此時竿裂,this.birth還是1990
        var fn  = function(y){
            return y - this.birth;
        };

        return fn.call({birth:3000},year);
    }
};


console.log(obj.getAge(2016));//結果是26
console.log(obj2.getAge(2016));//-984
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市照弥,隨后出現(xiàn)的幾起案子腻异,更是在濱河造成了極大的恐慌,老刑警劉巖这揣,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件悔常,死亡現(xiàn)場離奇詭異,居然都是意外死亡给赞,警方通過查閱死者的電腦和手機萝喘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來节吮,“玉大人屑咳,你說我怎么就攤上這事≌涎模” “怎么了罐旗?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長唯蝶。 經常有香客問我九秀,道長,這世上最難降的妖魔是什么粘我? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任鼓蜒,我火速辦了婚禮,結果婚禮上征字,老公的妹妹穿的比我還像新娘都弹。我一直安慰自己,他們只是感情好匙姜,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布畅厢。 她就那樣靜靜地躺著,像睡著了一般氮昧。 火紅的嫁衣襯著肌膚如雪框杜。 梳的紋絲不亂的頭發(fā)上浦楣,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天,我揣著相機與錄音咪辱,去河邊找鬼振劳。 笑死,一個胖子當著我的面吹牛油狂,可吹牛的內容都是我干的历恐。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼专筷,長吁一口氣:“原來是場噩夢啊……” “哼弱贼!你這毒婦竟也來了?” 一聲冷哼從身側響起仁堪,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤哮洽,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后弦聂,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鸟辅,經...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年莺葫,在試婚紗的時候發(fā)現(xiàn)自己被綠了匪凉。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡捺檬,死狀恐怖再层,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情堡纬,我是刑警寧澤聂受,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站烤镐,受9級特大地震影響蛋济,放射性物質發(fā)生泄漏。R本人自食惡果不足惜炮叶,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一碗旅、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧镜悉,春花似錦祟辟、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至吼具,卻和暖如春被芳,著一層夾襖步出監(jiān)牢的瞬間馍悟,已是汗流浹背剩晴。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留赞弥,地道東北人毅整。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓绽左,卻偏偏與公主長得像,于是被迫代替她去往敵國和親拼窥。 傳聞我的和親對象是個殘疾皇子戏蔑,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內容

  • 函數(shù)函數(shù)定義與調用變量作用域全局變量方法高階函數(shù)閉包箭頭函數(shù)$generator$ 函數(shù) 函數(shù)定義與調用 定義函數(shù)...
    染微言閱讀 577評論 0 5
  • 本文是大神廖雪峰的JavaScript教程學習筆記总棵。并不是教程,如有需要改含,請前往廖雪峰大神大博客. 一情龄、函數(shù)定義和...
    0o凍僵的企鵝o0閱讀 484評論 1 3
  • 函數(shù)就是最基本的一種代碼抽象的方式。 定義函數(shù)function abs(x) {if (x >=0){return...
    _我和你一樣閱讀 439評論 0 0
  • 本文只是關于JavaScript函數(shù)的一些入門介紹,寫的有些寬泛和簡單,目的是對JavaScript的函數(shù)有一個大...
    小松_路飛閱讀 515評論 0 2
  • 在JavaScript中捍壤,函數(shù)即對象骤视,程序可以隨意操控它們。比如鹃觉,JavaScript可以把函數(shù)賦值給變量专酗,或者作...
    kissLife閱讀 897評論 0 0