Javascript學習---函式物件
阿新 • • 發佈:2018-11-07
我們已經知道Javascript裡的值都有對應的型別,函式始終特殊的值,它的型別是物件
name屬性
函式物件包含一些可用的物件,例如name屬性
function sayHi() {
alert("Hi");
}
alert(sayHi.name); // sayHi
顯然,name屬性返回函式的名字
有趣的是,函式名字的指配是靈活的,例如:
let sayHi = function() {
alert("Hi");
}
alert(sayHi.name); // sayHi (works!)
當函式名是預設值的時候也起作用,例如:
function f(sayHi = function() {}) { alert(sayHi.name); // sayHi (works!) } f();
同樣,物件的方法也有name屬性,例如:
let user = {
sayHi() {
// ...
},
sayBye: function() {
// ...
}
}
alert(user.sayHi.name); // sayHi
alert(user.sayBye.name); // sayBye
length屬性
函式的length屬性返回函式引數的個數,例如:
在這裡我們可以看出,rest引數並不會被計算進去function f1(a) {} function f2(a, b) {} function many(a, b, ...more) {} alert(f1.length); // 1 alert(f2.length); // 2 alert(many.length); // 2
自定義屬性
除了函式的內建屬性,我們可以新增自定義屬性到函式中,例如新增counter屬性來放回函式被呼叫次數:
這裡需要注意的是,sayHi.counter=0來指定counter的值並不意味著counter是該函式的本地變數function sayHi() { alert("Hi"); // let's count how many times we run sayHi.counter++; } sayHi.counter = 0; // initial value sayHi(); // Hi sayHi(); // Hi alert( `Called ${sayHi.counter} times` ); // Called 2 times
函式的自定屬性特性有時候可以用來當做閉包使用,例如:
function makeCounter() {
// instead of:
// let count = 0
function counter() {
return counter.count++;
};
counter.count = 0;
return counter;
}
let counter = makeCounter();
alert( counter() ); // 0
alert( counter() ); // 1
相比於閉包,如果count存在於外部變數中,那麼外部程式碼將無法訪問count,只有巢狀函式才可以修改它,例如:
function makeCounter() {
function counter() {
return counter.count++;
};
counter.count = 0;
return counter;
}
let counter = makeCounter();
counter.count = 10;
alert( counter() ); // 10
命名函式表示式
先看下面兩個例子:
let sayHi = function(who) {
alert(`Hello, ${who}`);
};
現在我們為函式表示式加多一個名字,如下:
let sayHi = function func(who) {
alert(`Hello, ${who}`);
};
對於新增的函式名字,我們不能夠直接在外部呼叫,否則會報錯,例如:
let sayHi = function func(who) {
alert(`Hello, ${who}`);
};
sayHi("John"); // Hello, John
func("Jonh"); //error
這是因為命名函式表示式的名字(func)有以下兩個特性:
(1)它只能在函式內部被引用或呼叫;
(2)在函式外部函式名是不可見的,如上邊的例子;
那麼使用命名函式表示式有什麼好處呢?常見的作用是用於內部的自身呼叫,例如下面的例子:
let sayHi = function(who) {
if (who) {
alert(`Hello, ${who}`);
} else {
sayHi("Guest");
}
};
這裡sayHi()函式在內部呼叫了自身,顯然這沒什麼問題,但是考慮一下下面這種情況:
let sayHi = function(who) {
if (who) {
alert(`Hello, ${who}`);
} else {
sayHi("Guest"); // Error: sayHi is not a function
}
};
let welcome = sayHi;
sayHi = null;
welcome(); // Error, the nested sayHi call doesn't work any more!
很明顯,sayHi的值如果發生變化的話,其內部的自身呼叫也要改變。為了解決這種情況,命名函式表示式的作用就很明顯,如下:
let sayHi = function func(who) {
if (who) {
alert(`Hello, ${who}`);
} else {
func("Guest"); // Now all fine
}
};
let welcome = sayHi;
sayHi = null;
welcome(); // Hello, Guest (nested call works)
這裡要注意一點是,函式“內部名”為命名函式表示式所有,普通的函式宣告並不具備這樣的語法特性。