1. 程式人生 > >理解argument和 callee 屬性

理解argument和 callee 屬性

arguments

  javascript中的函式定義並未指定函式形參的型別,函式呼叫也未對傳入的實參值做任何型別檢查。實際上,javascript函式呼叫甚至不檢查傳入形參的個數

function add(x){
return x+1;
}
console.log(add(1));//2
console.log(add('1'));//'11'
console.log(add());//NaN
console.log(add(1,2));//2

同名形參

在非嚴格模式下,函式中可以出現同名形參,且只能訪問最後出現的該名稱的形參

function add(x,x,x){
return x;
}
console.log(add(1,2,3));//3

  而在嚴格模式下,出現同名形參會丟擲語法錯誤

function add(x,x,x){
'use strict';
return x;
}
console.log(add(1,2,3));//SyntaxError

引數個數

  當實參比函式宣告指定的形參個數要少,剩下的形參都將設定為undefined值
function add(x,y){
console.log(x,y);//1 undefined
}
add(1);

  常常使用邏輯或運算子給省略的引數設定一個合理的預設值

function add(x,y){
y = y || 2;
console.log(x,y);//1 2
}
add(1);

[注意]實際上,使用y || 2是不嚴謹的,顯式地設定假值(undefined、null、false、0、-0、''、NaN)也會得到相同的結果。所以應該根據實際場景進行合理設定

  當實參比形參個數要多時,剩下的實參沒有辦法直接獲得,需要使用即將提到的arguments物件

  javascript中的引數在內部是用一個數組來表示的。函式接收到的始終都是這個陣列,而不關心陣列中包含哪些引數。在函式體內可以通過arguments物件來訪問這個引數陣列,從而獲取傳遞給函式的每一個引數。arguments物件並不是Array的例項,它是一個類陣列物件,可以使用方括號語法訪問它的每一個元素
function add(x){
console.log(arguments[0],arguments[1],arguments[2])//1 2 3
return x+1;
}
add(1,2,3);

  arguments物件的length屬性顯示實參的個數,函式的length屬性顯示形參的個數
	
function add(x,y){
console.log(arguments.length)//3
return x+1;
}
add(1,2,3);
console.log(add.length);//2

  形參只是提供便利,但不是必需的

function add(){
return arguments[0] + arguments[1];
}
console.log(add(1,2));//3

物件引數

  當一個函式包含超過3個形參時,要記住呼叫函式中實參的正確順序實在讓人頭疼
function arraycopy(/*array*/from,/*index*/form_start,/*array*/to,/*index*/to_start,/*integer*/length){
//todo
}

通過名/值對的形式來傳入引數,這樣引數的順序就無關緊要了。定義函式的時候,傳入的實參都寫入一個單獨的物件之中,在呼叫的時候傳入一個物件,物件中的名/值對是真正需要的實引數據
function easycopy(args){
arraycopy(args.from,args.form_start || 0,args.to,args.to_start || 0, args.length);
}
var a = [1,2,3,4],b =[];
easycopy({form:a,to:b,length:4});

同步

  當形參與實參的個數相同時,arguments物件的值和對應形參的值保持同步
function test(num1,num2){
console.log(num1,arguments[0]);//1 1
arguments[0] = 2;
console.log(num1,arguments[0]);//2 2
num1 = 10;
console.log(num1,arguments[0]);//10 10
}
test(1);

[注意]雖然命名引數和對應arguments物件的值相同,但並不是相同的名稱空間。它們的名稱空間是獨立的,但值是同步的
  但在嚴格模式下,arguments物件的值和形參的值是獨立的
function test(num1,num2){
'use strict';
console.log(num1,arguments[0]);//1 1
arguments[0] = 2;
console.log(num1,arguments[0]);//1 2
num1 = 10;
console.log(num1,arguments[0]);//10 2
}
test(1);

  當形參並沒有對應的實參時,arguments物件的值與形參的值並不對應

function test(num1,num2){
console.log(num1,arguments[0]);//undefined,undefined
num1 = 10;
arguments[0] = 5;
console.log(num1,arguments[0]);//10,5
}
test();

內部屬性

【callee】

  arguments物件有一個名為callee的屬性,該屬性是一個指標,指向擁有這個arguments物件的函式

  下面是經典的階乘函式(遞迴

function factorial(num){
if(num <=1){
return 1;
}else{
return num* factorial(num-1);
}
} 
console.log(factorial(5));//120
但是,上面這個函式的執行與函式名緊緊耦合在了一起,可以使用arguments.callee可以消除函式解耦
function factorial(num){
if(num <=1){
return 1;
}else{
return num* arguments.callee(num-1);
}
} 
console.log(factorial(5));//120

  但在嚴格模式下,訪問這個屬性會丟擲TypeError錯誤

function factorial(num){
'use strict';
if(num <=1){
return 1;
}else{
return num* arguments.callee(num-1);
}
} 
//TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
console.log(factorial(5));

這時,可以使用具名的函式表示式
var factorial = function fn(num){ if(num <=1){ return 1; }else{ return num*fn(num-1); } }; console.log(factorial(5));//120