- 小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
目录
函数介绍形参个数与实参个数caller为调用当前函数的引用callee为函数本身callee案例:所有递归:(阶乘函数,斐波那契数列...)
零 函数介绍
1) 函数定义
专门用于封装代码,是一段可以随时被反复执行的代码块
2) 函数注意点
- 一个函数可以有形参也可以没有形参
- 一个函数可以有返回值也可以没有返回值
return的作用和break相似,所以return后不能编写任何语句(执行不到). break作用:立即结束switch语句或者循环语句.return作用:立即结束当前所在函数
2) arguments 类数组 转 数组的4种方式
function fn(a,b){
let args = [...arguments];
let args1 = Array.from(arguments);
let args2 = [].slice.call(arguments);
let args3 = Array.prototype.slice.call(arguments);
console.log(arguments, args, args1, args2, args3);
};
fn(1,2);
3) slice的实现 [] => [] 或 类数组 => []
call方法是将splice操作的对象指向argument
Array.prototype.slice = function(start,end){
var result = new Array();
start = start || 0;
end = end || this.length;
// this指向调用的对象,当用了call后,能够改变this的指向,也就是指向传进来的对象,这是关键
for(var i = start; i < end; i++){
result.push(this[i]);
}
return result;
};
let a =[1,2,3,4]; let b = a.slice1();
console.log(b); // [1,2,3,4]
一 形参个数 与 实参个数
形参个数:函数名.length或者arguments.callee.length.实参个数:arguments.length
function fn(a,b,c){
console.log('形参的个数:',fn.length);
console.log('形参的个数:',arguments.callee.length);
console.log('arguments对象:', arguments);
console.log('实参的个数:',arguments.length);
// callee 返回一个正在被执行函数的引用 (这里常用来递归匿名函数本身 但是在严格模式下不可行)
// callee 是arguments对象的一个成员 表示对函数对象本身的引用 它有个length属性(代表形参的长度)
console.log('函数本身:',arguments.callee === fn);
console.log('函数的调用者:',fn.caller); // caller 返回一个调用当前函数的引用 如果是由顶层调用的话 则返回null
console.log('函数的名字:',fn.name);
}
fn(1,2,3);
// 形参的个数: 3
// 形参的个数: 3
// arguments对象: Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
// 实参的个数: 3
// 函数本身: false
// 函数的调用者: null
// 函数的名字: fn1
二 caller为 调用当前函数的引用
字面意思caller直接翻译为调用者,callee翻译为被召者
ECMAScript 5也规范化了另一个
函数对象的属性caller。这个属性中保存着调用当前函数的函数的引用,如果是在全局作用域中调用当前函数,它的值为 null。
var callerTest = function() {
console.log(callerTest.caller);
} ;
function a() {
callerTest() ;
}
callerTest() ;//输出null
a(); // a() { callerTest(); }
caller可以认为那个函数调用了它,它就指向谁
三 callee为函数本身
callee为函数本身, 使用场景递归调用
arguments是一个
类数组对象,它包含着所有传入函数中的参数。这个对象有一个名叫做callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数
1) 案例: 所有递归:(阶乘函数,斐波那契数列...)
当函数名被修改,递归调用就会出现问题.
function factorial(num){
if(num === 1){
return 1;
}else{
return num * factorial(num - 1);
}
}
console.log(factorial(5)); //120
//递归调用时: 函数名被修改就会有问题
var fn1 = factorial;
console.log(fn1(5)); //120
factorial = function(){
return 0
};
// 函数的执行结果 错误
console.log(fn1(5));//0
console.log(factorial(5));//0
所以, 使用 arugments.callee 可以解决函数名被修改的问题.
function factorial(num){
if(num === 1){
return 1;
}else{
return num * arguments.callee(num - 1);
}
}
重写后的函数体中没有函数名,无论引用的函数使用任何名称时,都能保证递归的正常调用。
参考
总结
形参个数:函数名.length或者arguments.callee.length.实参个数:arguments.lengthcaller直接翻译为调用者,callee翻译为被召者callee为函数本身, 使用场景递归调用caller可以认为那个函数调用了它,它就指向谁- 注意:
callee和caller在严格模式下会有问题. arguments来保存函数的实参.callee指向当前函数.caller指向调用当前函数的函数类数组转数组的4种方式