我们来看一个函数定义表达式:
var f=function a(){ console.log(arguments.callee.name);//返回当前执行函数的 name };
f();// a
可能有人觉得奇怪哈,很正常,因为一般我们不这么写,要么不带 a ,要么就直接用函数声明语句了,不过这种写法有它的优势,用来递归的时候很方便,详情 戳这里;
这里主要来分析 a 的作用域的,上面的例子就为证明一点:
赋值给 f 的函数名称是 a ,不是 f
关键是,这个 a 的作用域问题,我们在 f 执行完后,访问 a:
报错了,证明 a 不是全局变量,实际上书上也是这么说的:
测试下,逻辑上没有问题:
不过我们不仅于此,我们在函数内给 a 重新赋值:
var f = function a() { a = 3; console.log(a); }; f();
返回的是函数本身,说明赋值失败了:
严格模式下,报错,字面理解就是赋值给了常量(注意 , ES6 新增了常量 const,对于常量是不能重复赋值的):
这说明:
函数定义表达式中带函数名称的,函数名称只能作为常量在函数体内访问,不可以被重新赋值的,非严格模式下静默失败,严格模式下报错;
既然知道了这个,如果在函数体内依然要给 a 赋值也不是不行,换成变量就可以了;
var f = function a() { var a = 3; console.log(a); }; f();//返回 3
当然这样就不能继续用 a 来访问原来的函数了,虽然还有其他办法,但是这样修改明显是不合适的,可读性不好;
另外,在函数声明语句中是可以的修改函数名称,比如:
function a() { a = 3; console.log(a); } a();//3,a 变成 3
但是,放在 IIFE 中,又不行了;
(function a() { a = 3; console.log(a);//函数,修改失败; })()
a;//error not defined;
当然,var 仍然是可行的,
(function a() { var a = 3; console.log(a);//3 成功 })()
对于 IIFE 中执行失败的解释,我猜测:
() 强制 js 引擎 把里面的函数声明语句当成了表达式,那么这种情况下,这个效果不就等价于 带名称的函数定义表达式么?这个时候,函数名称应该也是局部变量且只能在函数内部访问,不可修改;
文档上是这么说的:
参考资料:
https://stackoverflow.com/questions/24021489/variable-in-function-body-and-function-itself-have-the-same-name-javascript/24022076#24022076
https://stackoverflow.com/questions/15129504/why-are-anonymous-function-expressions-and-named-function-expressions-initialize