关于函数
函数的名字只是一个指向函数地址的指针,它并不能代表这个函数,真正执行的是括号后边的代码段,所以,一个代码段可以由多个不同名的指针指向
以fn1命名的一个函数,并不是代表括号后边的代码段只属于fn1,只是有一个名为fn1的指针指向它,它可以把这个代码段复制给fn2 ,所以fn2()也可以执行这个代码段
function fn1(){
return 1
}
let fn2=fn1
console.log(fn2()) // 1
console.log(fn1()) // 1
同时代码段内部是可以累积执行次数的,也就是说,代码段内部是不会分辨出是由哪个指针执行的命令的
这里我们设置一个变量为1,没执行一次,i+1,当通过fn2这个指针第一次执行这个代码段时,i+1输出2, 下一次通过fn1这个指针执行,i继续+1输出3
var i=1
function fn1(){
return ++i
}
let fn2=fn1
console.log(fn2()) // 2
console.log(fn1()) // 3
所以说,函数的名字不是很重要,重要的是函数名后边的代码段,但是有一种情况必须要注意,那就是在使用递归的时候
fn1这个函数求传入参数的递归乘积,如果每次递归重新调用fn1的时候都是引用fn1这个指针,那么一旦fn1被重新定义了之后指针就会改变指向,就会出现错误。
下边这一段代码 当fn1执行一次的时候,fn1的指针又重新指向了另一个代码段,所以最后结果是5*1=5。
function fn1(num){
if(num<=1){
return 1;
}else{
return num * fn1(num-1)
}
}
let fn2=fn1
fn1=function(){
return 1
}
console.log(fn2(5)) //5
上面这种情况被称为代码的高耦合,耦合性就是代码段之间的联系太过于紧密,所以当有一小部分改变的时候,会影响整个代码段,从而出现错误。所以我们在写代码的时候一定要注意各个代码段之间尽量不要有太高的耦合性。为了解决上述问题,我们可以使用函数内部自带的一个对象arguments,arguments一般用于显示函数内部传入的参数,是一个伪数组,但它有一个.callee方法,这个方法直接指向arguments所在的代码段
在这里我们将fn1(num-1)替换成arguments.callee(num-1),在每次调用这个函数的时候,arguments.callee(num-1)就跟名为fn1的指针没有任何关系,它只会指向自己所在的代码段,所以当fn1被改变指向的时候,也不会对结果产生任何影响。
function fn1(num){
if(num<=1){
return 1;
}else{
return num * arguments.callee(num-1)
}
}
let fn2=fn1
fn1=function(){
return 1
}
console.log(fn2(5)) //120
注意:arguments在严格模式下是禁止使用的,因为比较耗费性能-_-||。。。
但是并不是没有解决的办法
这种情况 将fn1赋给fn函数,当fn变的时候,fn1是不变的,所以函数内部的指针并不会发生任何变化,只是相当于将函数返回值赋给了而另一个变量 let fn=(function fn1(num){ if(num>3){ return num*fn1(num-1) }else{ return 1 } }) console.log(fn(4)) //4 let fn2=fn; fn=null; console.log(fn2(5)) //20