對(duì)于面向?qū)ο缶幊痰恼Z(yǔ)言來(lái)說(shuō),對(duì)象是很重要的一個(gè)概念,而對(duì)于函數(shù)來(lái)說(shuō),每個(gè)函數(shù)實(shí)際上都是對(duì)象,每個(gè)函數(shù)都是Function類型的實(shí)例,而且與其他引用類型一樣具有屬性和方法。
函數(shù)聲明與函數(shù)表達(dá)式
通常有三種聲明函數(shù)的方法
- 使用函數(shù)聲明語(yǔ)法
function sum(num1, num2) {
return num1 + num2;
}
這也是最常用的方法
- 使用函數(shù)表達(dá)式定義函數(shù)
var sum = function (num1, num2) {
return num1 + num2;
};
可能會(huì)注意到function關(guān)鍵字后面沒(méi)有函數(shù)名,這是因?yàn)槭褂煤瘮?shù)表達(dá)式定義函數(shù)時(shí),通過(guò)變量sum就可以引用函數(shù)
- 使用Function構(gòu)造函數(shù)
var sum = new Function("num1", "num2", "return num1 + num2");
但是非常不推薦這種寫法,因?yàn)檫@種語(yǔ)法會(huì)導(dǎo)致解析兩次代碼(第一次解析ECMAScript代碼,第二次解析傳入構(gòu)造函數(shù)的參數(shù))從而影響性能
關(guān)于變量提升
對(duì)于1,2兩種聲明函數(shù)的方法有什么不同呢?看下面這個(gè)例子
// 使用函數(shù)聲明創(chuàng)建函數(shù)
console.log(sum(10,10)); //會(huì)打印出20
function sum(num1, num2) {
return num1 + num2;
};
// 使用函數(shù)表達(dá)式創(chuàng)建函數(shù)
console.log(add(10,10)); //會(huì)報(bào)錯(cuò)
var add = function(num1, num2) {
return num1 + num2;
};
實(shí)際上,解析器在執(zhí)行環(huán)境中加載數(shù)據(jù)時(shí),解析器會(huì)率先讀取函數(shù)聲明,并使其在執(zhí)行任何代碼之前可用,而至于函數(shù)表達(dá)式,則必須等到解析器執(zhí)行到它所在的代碼行才會(huì)真正被解釋執(zhí)行。
函數(shù)內(nèi)部屬性
在函數(shù)內(nèi)部,有兩個(gè)特殊的對(duì)象:arguments和this
arguments是一個(gè)類數(shù)組對(duì)象,包含著傳入函數(shù)的所有參數(shù),之前在基礎(chǔ)算法的時(shí)候已經(jīng)講過(guò)。但是arguments還有一個(gè)名叫callee屬性,該屬性是一個(gè)指針,指向擁有arguments對(duì)象的函數(shù)。具體用法之前寫過(guò)了,看這里
另一個(gè)比較特殊的對(duì)象就是this了,關(guān)于this知乎上@方方老師的這篇文章講的特別好
函數(shù)的屬性和方法
因?yàn)樵贓CMAScript中函數(shù)是對(duì)象,因此函數(shù)也有屬性和方法。
每個(gè)函數(shù)包含兩個(gè)屬性:length和prototype
length表示函數(shù)接受的參數(shù)的個(gè)數(shù)
function sayName(name) {
console.log(name);
}
function sum(sum1, sum2) {
return num1 + num2;
}
function sayHi() {
console.log("Hi!");
}
console.log(sayName.length); //1
console.log(sum.length); //2
console.log(sayHi.length); //0
另一個(gè)屬性prototype是保存引用類型所有實(shí)例方法的真正所在,比如toString()和valueOf()等方法都保存在prototype名下,prototype在實(shí)現(xiàn)繼承時(shí)非常重要,下一篇我們?cè)僦v。
每個(gè)函數(shù)都包含兩個(gè)非繼承來(lái)的方法:apply()和call()
apply()和call()都是在特定的作用域中調(diào)用函數(shù),等于設(shè)置函數(shù)體內(nèi)this的值,他們的區(qū)別在于:
apply()接受兩個(gè)參數(shù):一個(gè)是在其中運(yùn)行函數(shù)的作用域,另一個(gè)是參數(shù)數(shù)組,既可以是Array實(shí)例,也可以是arguements對(duì)象。
call()第一個(gè)參數(shù)和apply()一樣,但是傳遞參數(shù)的時(shí)候,必須逐個(gè)例舉出來(lái)。
function sum(num1, num2) {
return num1 + num2;
}
function callSum1(num1, num2) {
return sum.apply(this, arguments); //傳入arguments字符串
}
function callSum2(num1, num2) {
return sum.apply(this, [num1,num2]); //傳入數(shù)組
}
function callSum3(num1, num2) {
return sum.call(this, num1, num2); //使用call必須把參數(shù)列舉出來(lái)
}
console.log(callSum1(10,10)); //20
console.log(callSum2(10,10)); //20
console.log(callSum3(10,10)); //20
既然apply()和call()的參數(shù)有作用域,那么是用來(lái)干什么的呢?看下面的例子:
window.color = "red";
var 0 = { color: "blue" };
function sayColor() {
console.log(this.color);
}
sayColor(); //red
sayColor.call(this) //red
sayColor.call(window) //red
sayColor.call(o) //blue
是不是this的值又懵了?如果懵了,就翻上去看方方老師那篇文章。
沒(méi)錯(cuò),apply()和call()的作用就是擴(kuò)充函數(shù)的作用域
大概就是這么多了,書上這一章的內(nèi)容我反復(fù)看了好幾遍才理解,所以學(xué)習(xí)哪有什么捷徑,無(wú)他,唯手熟爾
那么,聰明的你,看完之后懂了沒(méi)有?
下一篇準(zhǔn)備講原型