JavaScript中的函式
JS中的函式給我的感覺還是蠻新奇的,以前只學過C和Java,都是不可以函式巢狀的強型別語言,(儘管JDK10以後,Java引入了局部型別推斷(Local-Variable Type Inference),即我們平時說的var),弱型別語言的一些特性,我還是需要些時間慢慢去適應
目錄
一. 弱型別語言無法輸出地址
弱型別語言的方法雖然可以輸出,但是得到的並不是期望的地址值,而是整個函式體,儘管JS也有堆和棧的概念,但是地址不會被輸出
<script> function testMethod() { alert("我真帥"); } testMethod(); console.log(testMethod); // 控制檯中輸出 內容同下 document.write(testMethod); // function testMethod() { alert("我真帥"); } </script>
輸出到瀏覽器螢幕上的是 function testMethod() { alert("我真帥"); },而在控制檯中輸出則更規範,保留了程式碼格式,一般都在控制檯中輸出
二. 3種函式定義方式
3種定義方式,可以總的被歸納為兩種,如下所示
-
函式宣告
-
函式表示式
其中,函式表示式還可以再進一步細分為命名函式表示式和匿名函式表示式
(1)函式宣告
<script>
function test() {
console.log("函式宣告");
}
// test();
</script>
如上所示,一個函式便被聲明瞭,但是不會執行,因為此時沒有JS程式碼呼叫它,此時只需要把註釋放開,便可在控制檯看到輸出
(2.1)命名函式表示式
<script>
var named = function abc () {
console.log("命名函式表示式");
}
named();
</script>
命名函式表示式的命名二字,表現在function後面的“abc”那,但是實際上若想呼叫這個函式還是需要named();這樣呼叫,後面的“abc”基本上是沒有任何意義的,。因此實際開發一般都是使用匿名函式表示式
(2.2)匿名函式表示式
<script> var unnamed = function () { console.log("匿名函式表示式"); } unnamed(); </script>
匿名函式表示式結構更加清晰,刪除了無用的命名
那麼,儘管命名函式表示式沒用,那麼它們的區別在哪裡呢?
答案其實就是命名那
<script>
// (1)函式宣告
function test() {
console.log("函式宣告");
}
// (2)函式表示式
// (2).1 命名函式表示式
var named = function abc () {
console.log("命名函式表示式");
}
// (2).2 匿名函式表示式
var unnamed = function () {
console.log("匿名函式表示式");
}
// (2).1和(2).2的區別在於各自的name屬性 2.1為abc 2.2為unnamed 此外,以函式宣告方式定義函式同樣有name 即它本身
console.log("test.name = " + test.name); // test
console.log("named.name = " + named.name); // abc 唯一一點不同之處 開發一般都用匿名
console.log("unnamed.name = " + unnamed.name); // unnamed
</Script>
如上程式碼
可以看到,無論是函式宣告還是匿名函式表示式,方法的name屬性值都是各自的方法名,唯獨命名函式表示式是function後面跟著的變數名“abc”,區別僅在於此
三. 形參和實參列表
JavaScript中的形參因為弱型別語言的緣故,不再需要定義變數資料型別,直接寫名字即可,且不限制傳遞引數個數(類似於Java的JDK5引入的可變引數,不過功能更加強大),但這樣的同時也會引發一些問題,比如傳遞的引數個數和定義的形參個數不同,此時需要以arguments物件取出實參。 具體看下面的程式碼
<script>
function js (a,b) {
// 形參相當於 var a,b;
if (js.length > arguments.length) {
console.log("形參多了");
} else if (js.length < arguments.length) {
console.log("實參多了");
} else {
console.log("相等");
}
for (var i = 0;i<arguments.length;i++){
alert(arguments[i]);
}
js(1,2,3,undefined,null,NaN);
</script>
形參定義了兩個,但實際傳遞的引數有5個,此時如果想使用其餘被傳遞的引數,則需要使用arguments物件獲取,注意,arguments是物件而不是陣列,arguments[0]只是其一個屬性,而這個屬性是傳遞的實參的副本
除此之外,形參還和arguments物件的屬性存在對映關係,若修改了形參值會通過對映改變arguments物件屬性的值(但二者實際上並非指向同一塊記憶體),即形參值,但是也存在一定的約束關係,形參值只能修改和實參值共有的部分,如下所示
<script>
function testArgs(a,b,c,d) {
// 相當於 var a,b,c,d;
a = 11;
b = 22;
c = 33;
d = 44;
console.log("arguments[0] = " + arguments[0]); // 11
console.log("arguments[1] = " + arguments[1]); // 22
console.log("arguments[2] = " + arguments[2]); // 33
console.log("arguments[3] = " + arguments[3]); // undefined
//由此可見 這種對映關係只存在於實參和形參的共有部分
}
testArgs(1,2,3);
</script>
實際被傳遞的引數只有3個,但此時形參定義了4個,那麼arguments陣列的屬性也只有arguments[0],arguments[1],arguments[2],此時檢視arguments[3]自然是undefined