JS中函數定義時不需要指定參數的類型,函數調用時也不會對傳入的參數進行類型檢查,甚至參數的個數也不做檢查,了解這些特殊情況,避免開發出錯。
參數個數
當實參比形參的個數少時,多余的形參會被設置成undefined。
function fn(a,b,c){
console.log(c) // undefined
}
fn(1,2)
當實參比形參的個數多時,多余的實參在函數中無法直接獲取到,可以通過arguments對象獲取。
function fn(a,b) {
console.log(arguments[0],arguments[1],arguments[2]) // 1 2 3
}
fn(1,2,3)
JS函數中的參數在內部是用一個數組表示的,可以通過arguments對象訪問這個參數數組,從而獲取到傳入給函數的每一個參數。
注意: arguments對象是一個類數組對象,不是Array對象的實例。可以使用方括號語法訪問每一個元素。
arguments對象的length屬性顯示實參的個數,函數的length屬性顯示形參的個數。
function fn(a,b) {
console.log(arguments.length) // 3
console.log(fn.length) // 2
}
fn(1,2,3)
參數同步
在嚴格模式下,arguments對象的值和形參是獨立的。在非嚴格模式下,它們的值是同步的。
// 示例1
function fn(a) {
'use strict'
console.log(a, arguments[0]) // 1 1
a = 2
console.log(a, arguments[0]) // 2 1
arguments[0] = 3
console.log(a, arguments[0]) // 2 3
}
fn(1)
// 示例2
function fn(a) {
console.log(a, arguments[0]) // 1 1
a = 2
console.log(a, arguments[0]) // 2 2
arguments[0] = 3
console.log(a, arguments[0]) // 3 3
}
fn(1)
callee屬性
arguments對象的callee屬性是一個指針,指向擁有這個arguments對象的函數。
注意: 嚴格模式下禁止使用該屬性,會報錯
// 階層函數
function factorial(num) {
if(num <=1) {
return 1
} else {
return num * factorial(num - 1)
}
}
factorial(3) // 6
上面的函數有一個問題,就是函數的執行和函數名耦合在了一起,這時可以使用callee屬性解決這個問題。
function factorial(num) {
if(num <=1) {
return 1
} else {
return num * arguments.callee(num - 1)
}
}
factorial(3) // 6
由於callee屬性在嚴格模式下報錯,可以使用具名函數表達式。
var factorial = function fn(num){
if(num <=1){
return 1
}else {
return num * fn(num - 1)
}
}
factorial(3) // 6
caller屬性
arguments對象的caller屬性不是一個標准屬性,不贊成用於生產環境,但瀏覽器都支持它。該屬性保存了調用當前函數的函數的引用,如果在全局作用域中調用當前函數,它的值是null。
注意: 嚴格模式下禁止使用該屬性,會報錯
// 示例1
function outer() {
inner()
}
function inner() {
// inner是當前函數,outer是調用當前函數的函數
console.log(inner.caller) // outer() { inner() }
}
outer()
// 示例2
function inner() {
console.log(inner.caller)
}
inner() // null
函數重載
函數重載簡單理解就是同一個函數,可以根據不同的參數(比如類型不同或數量不同)執行不同的處理邏輯。
由於JS無法為同一個函數編寫不同的定義標簽,所以真正的重載是做不到的,只能通過檢查傳入函數中參數的類型和數量作出不同的反應,來模仿方法的重載。
function doAdd(){
if(arguments.length == 1){
alert(arguments[0] + 10);
}else if(arguments.length == 2){
alert(arguments[0] + arguments[1]);
}
}
doAdd(10);//20
doAdd(30,20);//50
參數傳遞
【基本類型值】向參數傳遞基本類型值時,被傳遞的值會復制給一個局部變量(命名參數或arguments對象中的一個元素)
function fn(num) {
num += 10
return num
}
var count = 10
var result = fn(count)
console.log(count) // 10 原始值不會改變
console.log(result) // 20
【引用類型值】向參數傳遞引用類型值時,被傳遞的值的引用地址復制給一個局部變量,所以局部變量的變化會反映到外部函數上。
function fn(obj) {
obj.name = 'hello'
}
var person = new Object()
fn(person)
console.log(person.name) // 'hello'
如果在函數內部重寫引用類型的形參,被傳遞的值就會成為一個局部變量,局部變量會在函數執行結束后立即銷毀
function fn(obj) {
obj = new Object();
obj.name = 'hello';
}
var person = new Object()
fn(person)
console.log(person.name) // undefined