JS筆記 2.函數(shù)

2. 函數(shù)

2.1 函數(shù)定義和調(diào)用

定義函數(shù)
有兩種方法既荚,一種是:

function abs(x) {
    if (x >= 0) {
        return x;
    } else {
        return -x;
    }
}

另一種是:

var abs = function (x) {
    if (x >= 0) {
        return x;
    } else {
        return -x;
    }
};//末尾添加 ; 構(gòu)成完整語(yǔ)法

兩種定義方法完全等價(jià)待笑。

函數(shù)調(diào)用
按順序傳入?yún)?shù)即可乳幸。

js允許傳入任意個(gè)參數(shù)肝集,因此傳入的參數(shù)比定義的參數(shù)多也沒(méi)有問(wèn)題瞻坝,雖然函數(shù)內(nèi)部并不需要這些參數(shù)。

傳入的參數(shù)少也不會(huì)出錯(cuò)杏瞻。

arguments
js有一個(gè)關(guān)鍵字 arguments ,它只在函數(shù)內(nèi)部起作用所刀,利用 arguments 可以獲得調(diào)用者傳入的所有參數(shù)。

rest

2.2 變量作用域與解構(gòu)賦值

如果一個(gè)變量在函數(shù)體內(nèi)部申明捞挥,則該變量的作用域?yàn)檎麄€(gè)函數(shù)體浮创,在函數(shù)體外不可引用該變量。

如果兩個(gè)不同的函數(shù)各自申明了同一個(gè)變量砌函,那么該變量只在各自的函數(shù)體內(nèi)起作用斩披。換句話(huà)說(shuō),不同函數(shù)內(nèi)部的同名變量互相獨(dú)立讹俊,互不影響垦沉。

由于JavaScript的函數(shù)可以嵌套,此時(shí)仍劈,內(nèi)部函數(shù)可以訪(fǎng)問(wèn)外部函數(shù)定義的變量厕倍,反過(guò)來(lái)則不行。

JavaScript的函數(shù)在查找變量時(shí)從自身函數(shù)定義開(kāi)始贩疙,從“內(nèi)”向“外”查找讹弯。如果內(nèi)部函數(shù)定義了與外部函數(shù)重名的變量,則內(nèi)部函數(shù)的變量將“屏蔽”外部函數(shù)的變量屋群。

變量提升
JavaScript的函數(shù)定義會(huì)先掃描整個(gè)函數(shù)體的語(yǔ)句闸婴,把所有申明的變量“提升”到函數(shù)頂部。由于JavaScript的這一怪異的“特性”芍躏,我們?cè)诤瘮?shù)內(nèi)部定義變量時(shí),請(qǐng)嚴(yán)格遵守在函數(shù)內(nèi)部首先申明所有變量這一規(guī)則降狠。最常見(jiàn)的做法是用一個(gè)var申明函數(shù)內(nèi)部用到的所有變量:

function foo() {
    var
        x = 1, // x初始化為1
        y = x + 1, // y初始化為2
        z, i; // z和i為undefined
    // 其他語(yǔ)句:
    for (i=0; i<100; i++) {
        ...
    }
}

全局作用域
不在任何函數(shù)內(nèi)定義的變量就具有全局作用域对竣。實(shí)際上,JavaScript默認(rèn)有一個(gè)全局對(duì)象window榜配,全局作用域的變量實(shí)際上被綁定到window的一個(gè)屬性否纬。

由于函數(shù)定義有兩種方式,以變量方式var foo = function () {}定義的函數(shù)實(shí)際上也是一個(gè)全局變量蛋褥,因此临燃,頂層函數(shù)的定義也被視為一個(gè)全局變量,并綁定到window對(duì)象。

'use strict';

function foo() {
    alert('foo');
}

foo(); // 直接調(diào)用foo()
window.foo(); // 通過(guò)window.foo()調(diào)用

JavaScript實(shí)際上只有一個(gè)全局作用域膜廊。任何變量(函數(shù)也視為變量)乏沸,如果沒(méi)有在當(dāng)前函數(shù)作用域中找到,就會(huì)繼續(xù)往上查找爪瓜,最后如果在全局作用域中也沒(méi)有找到蹬跃,則報(bào)ReferenceError錯(cuò)誤。

名字空間
全局變量會(huì)綁定到window上铆铆,不同的JavaScript文件如果使用了相同的全局變量蝶缀,或者定義了相同名字的頂層函數(shù),都會(huì)造成命名沖突薄货,并且很難被發(fā)現(xiàn)翁都。減少?zèng)_突的一個(gè)方法是把自己的所有變量和函數(shù)全部綁定到一個(gè)全局變量中。

// 唯一的全局變量MYAPP:
var MYAPP = {};

// 其他變量:
MYAPP.name = 'myapp';
MYAPP.version = 1.0;

// 其他函數(shù):
MYAPP.foo = function () {
    return 'foo';
};

局部作用域
由于JavaScript的變量作用域?qū)嶋H上是函數(shù)內(nèi)部谅猾,我們?cè)趂or循環(huán)等語(yǔ)句塊中是無(wú)法定義具有局部作用域的變量的:

'use strict';

function foo() {
    for (var i=0; i<100; i++) {
        //
    }
    i += 100; // 仍然可以引用變量i
}

為了解決塊級(jí)作用域荐吵,ES6引入了新的關(guān)鍵字let,用let替代var可以申明一個(gè)塊級(jí)作用域的變量:

'use strict';

function foo() {
    var sum = 0;
    for (let i=0; i<100; i++) {
        sum += i;
    }
    // SyntaxError:
    i += 1;
}

常量
由于var和let申明的是變量赊瞬,如果要申明一個(gè)常量先煎,在ES6之前是不行的,我們通常用全部大寫(xiě)的變量來(lái)表示“這是一個(gè)常量巧涧,不要修改它的值”薯蝎。ES6標(biāo)準(zhǔn)引入了新的關(guān)鍵字const來(lái)定義常量,const與let都具有塊級(jí)作用域谤绳。

解構(gòu)賦值
ES6引入了解構(gòu)賦值占锯,可以對(duì)多個(gè)變量同時(shí)賦值。

如果數(shù)組本身還有嵌套缩筛,也可以通過(guò)下面的形式進(jìn)行解構(gòu)賦值消略,注意嵌套層次和位置要保持一致。

解構(gòu)賦值還可以忽略某些元素瞎抛。

如果需要從一個(gè)對(duì)象中取出若干屬性艺演,也可以使用解構(gòu)賦值,便于快速獲取對(duì)象的指定屬性桐臊。

解構(gòu)賦值還可以使用默認(rèn)值胎撤,這樣就避免了不存在的屬性返回undefined的問(wèn)題。

var [x, y, z] = ['hello', 'JavaScript', 'ES6'];

let [x, [y, z]] = ['hello', ['JavaScript', 'ES6']];

let [, , z] = ['hello', 'JavaScript', 'ES6']; // 忽略前兩個(gè)元素断凶,只對(duì)z賦值第三個(gè)元素

var person = {
    name: '小明',
    age: 20,
    gender: 'male',
    passport: 'G-12345678',
    school: 'No.4 middle school',
    address: {
        city: 'Beijing',
        street: 'No.1 Road',
        zipcode: '100001'
    }
};
var {name, age, passport} = person;// name, age, passport分別被賦值為對(duì)應(yīng)屬性

var {name, address: {city, zip}} = person;//city:"Beijing", zip是undefined伤提,因?yàn)閷傩悦莦ipcode不是zip

let {name, passport:id} = person;//id:'G-12345678'

var {name, single=true} = person;// 如果person對(duì)象沒(méi)有single屬性,默認(rèn)賦值為true 

2.3 方法

xiaoming 綁定一個(gè)函數(shù)认烁,就可以做更多的事情肿男。比如介汹,寫(xiě)個(gè) age() 方法,返回 xiaoming 的年齡舶沛。

var xiaoming = {
    name: '小明',
    birth: 1990,
    age: function () {
        var y = new Date().getFullYear();
        return y - this.birth;
    }
};

xiaoming.age; // function xiaoming.age()
xiaoming.age(); // 今年調(diào)用是25,明年調(diào)用就變成26了

在一個(gè)方法內(nèi)部嘹承, this 是一個(gè)特殊變量,它始終指向當(dāng)前對(duì)象冠王,也就是 xiaoming 這個(gè)變量赶撰。

JavaScript 的函數(shù)內(nèi)部如果調(diào)用了 this ,如果以對(duì)象的方式調(diào)用柱彻,比如 xiaoming.age() 豪娜,該函數(shù)的 this 指向被調(diào)用的對(duì)象,也就是 xiaoming 哟楷;如果單獨(dú)調(diào)用函數(shù)瘤载,此時(shí)該函數(shù)的 this 指向全局對(duì)象,即 window 卖擅。

apply
要指定函數(shù)的this指向哪個(gè)對(duì)象鸣奔,可以用函數(shù)本身的apply方法,它接收兩個(gè)參數(shù)惩阶,第一個(gè)參數(shù)就是需要綁定的this變量挎狸,第二個(gè)參數(shù)是Array,表示函數(shù)本身的參數(shù)断楷。

用apply修復(fù)getAge()調(diào)用:

function getAge() {
    var y = new Date().getFullYear();
    return y - this.birth;
}

var xiaoming = {
    name: '小明',
    birth: 1990,
    age: getAge
};

xiaoming.age(); // 25
getAge.apply(xiaoming, []); // 25, this指向xiaoming, 參數(shù)為空

另一個(gè)與apply()相似的方法是call()锨匆,區(qū)別在于aplly()把參數(shù)打包成Array傳入,call()把參數(shù)按順序傳入冬筒。對(duì)普通函數(shù)調(diào)用恐锣,通常把this綁定為null,即:

Math.max.apply(null, [3, 5, 4]); // 5
Math.max.call(null, 3, 5, 4); // 5

2.4 高階函數(shù)

JavaScript的函數(shù)其實(shí)都指向某個(gè)變量舞痰。既然變量可以指向函數(shù)土榴,函數(shù)的參數(shù)能接收變量,那么一個(gè)函數(shù)就可以接收另一個(gè)函數(shù)作為參數(shù)响牛,這種函數(shù)就稱(chēng)之為高階函數(shù)玷禽。

map/reduce
map
由于map()方法定義在JavaScript的Array中,我們調(diào)用Array的map()方法娃善,傳入我們自己的函數(shù)论衍,就得到了一個(gè)新的Array作為結(jié)果。

'use strict';

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

var arr = [1,2,3,4,5,6,7,8,9,10];
var results = arr.map(pow);//map傳入的參數(shù)是pow聚磺,即函數(shù)對(duì)象本身
console.log(results);//1,4,9,16,25,36,49,64,81,100

reduce
Array的reduce()把一個(gè)函數(shù)作用在這個(gè)Array的[x1, x2, x3...]上,這個(gè)函數(shù)必須接收兩個(gè)參數(shù)炬丸,reduce()把結(jié)果繼續(xù)和序列的下一個(gè)元素做累積計(jì)算瘫寝。

var arr = [1, 3, 5, 7, 9];
arr.reduce(function (x, y) {
    return x + y;
}); // 25

fliter
filter用于把Array的某些元素過(guò)濾掉蜒蕾,然后返回剩下的元素。和map()類(lèi)似焕阿,Array的filter()也接收一個(gè)函數(shù)咪啡。和map()不同的是,filter()把傳入的函數(shù)依次作用于每個(gè)元素暮屡,然后根據(jù)返回值是true還是false決定保留還是丟棄該元素撤摸。

var
    r,
    arr = ['apple', 'strawberry', 'banana', 'pear', 'apple', 'orange', 'orange', 'strawberry'];

r = arr.filter(function (element, index, self) {
    return self.indexOf(element) === index;//true的話(huà)過(guò)濾
});//indexOf返回第一個(gè)元素的位置,后續(xù)重復(fù)元素位置與indexOf返回的位置不相等褒纲,所以被fliter過(guò)濾掉了

sort
Array的sort()方法默認(rèn)把所有元素先轉(zhuǎn)換為String再排序准夷,幸運(yùn)的是,sort()方法也是一個(gè)高階函數(shù)莺掠,它還可以接收一個(gè)比較函數(shù)來(lái)實(shí)現(xiàn)自定義的排序衫嵌。sort()方法會(huì)直接對(duì)Array進(jìn)行修改,它返回的結(jié)果仍是當(dāng)前Array彻秆。

//倒序排序
var arr = [10, 20, 1, 2];
arr.sort(function (x, y) {
    if (x < y) {
        return 1;
    }
    if (x > y) {
        return -1;
    }
    return 0;
}); // [20, 10, 2, 1]

every
every()方法可以判斷數(shù)組的所有元素是否滿(mǎn)足測(cè)試條件楔绞。

find
find()方法用于查找符合條件的第一個(gè)元素,如果找到了唇兑,返回這個(gè)元素酒朵,否則,返回undefined扎附。

findIndex
findIndex()和find()類(lèi)似蔫耽,也是查找符合條件的第一個(gè)元素,不同之處在于findIndex()會(huì)返回這個(gè)元素的索引帕棉,如果沒(méi)有找到针肥,返回-1。

forEach
forEach()和map()類(lèi)似香伴,它也把每個(gè)元素依次作用于傳入的函數(shù)慰枕,但不會(huì)返回新的數(shù)組。forEach()常用于遍歷數(shù)組即纲,因此具帮,傳入的函數(shù)不需要返回值。

2.5 閉包

函數(shù)作為返回值
此處參考廖雪峰老師的講解低斋,不再贅述 https://www.liaoxuefeng.com/wiki/1022910821149312/1023021250770016

2.6 generator

generator(生成器)是ES6標(biāo)準(zhǔn)引入的新的數(shù)據(jù)類(lèi)型蜂厅。一個(gè)generator看上去像一個(gè)函數(shù),但可以返回多次膊畴。generator和函數(shù)不同的是掘猿,generator由function定義(注意多出的號(hào)),并且唇跨,除了return語(yǔ)句稠通,還可以用yield返回多次衬衬。

調(diào)用generator對(duì)象有兩個(gè)方法,一是不斷地調(diào)用generator對(duì)象的next()方法改橘,next()方法會(huì)執(zhí)行g(shù)enerator的代碼滋尉,然后,每次遇到y(tǒng)ield x;就返回一個(gè)對(duì)象{value: x, done: true/false}飞主,然后“暫褪ㄏВ”。返回的value就是yield的返回值碌识,done表示這個(gè)generator是否已經(jīng)執(zhí)行結(jié)束了碾篡。如果done為true,則value就是return的返回值丸冕。
當(dāng)執(zhí)行到done為true時(shí)耽梅,這個(gè)generator對(duì)象就已經(jīng)全部執(zhí)行完畢,不要再繼續(xù)調(diào)用next()了胖烛。

第二個(gè)方法是直接用for ... of循環(huán)迭代generator對(duì)象眼姐,這種方式不需要我們自己判斷done。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末佩番,一起剝皮案震驚了整個(gè)濱河市众旗,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌趟畏,老刑警劉巖贡歧,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異赋秀,居然都是意外死亡利朵,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門(mén)猎莲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)绍弟,“玉大人,你說(shuō)我怎么就攤上這事著洼≌燎玻” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵身笤,是天一觀(guān)的道長(zhǎng)豹悬。 經(jīng)常有香客問(wèn)我,道長(zhǎng)液荸,這世上最難降的妖魔是什么瞻佛? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮娇钱,結(jié)果婚禮上涤久,老公的妹妹穿的比我還像新娘涡尘。我一直安慰自己忍弛,他們只是感情好响迂,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著细疚,像睡著了一般蔗彤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上疯兼,一...
    開(kāi)封第一講書(shū)人閱讀 49,730評(píng)論 1 289
  • 那天然遏,我揣著相機(jī)與錄音,去河邊找鬼吧彪。 笑死待侵,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的姨裸。 我是一名探鬼主播秧倾,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼傀缩!你這毒婦竟也來(lái)了那先?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤赡艰,失蹤者是張志新(化名)和其女友劉穎售淡,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體慷垮,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡揖闸,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了料身。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片汤纸。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖惯驼,靈堂內(nèi)的尸體忽然破棺而出蹲嚣,到底是詐尸還是另有隱情,我是刑警寧澤祟牲,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布隙畜,位于F島的核電站,受9級(jí)特大地震影響说贝,放射性物質(zhì)發(fā)生泄漏议惰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一乡恕、第九天 我趴在偏房一處隱蔽的房頂上張望言询。 院中可真熱鬧俯萎,春花似錦、人聲如沸运杭。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)辆憔。三九已至撇眯,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間虱咧,已是汗流浹背熊榛。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留腕巡,地道東北人玄坦。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像绘沉,于是被迫代替她去往敵國(guó)和親煎楣。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容