Javascript 为什么函数名在分配给变量时消失?
我正试图深入了解Javascript的工作原理,下面的代码困扰着我:Javascript 为什么函数名在分配给变量时消失?,javascript,Javascript,我正试图深入了解Javascript的工作原理,下面的代码困扰着我: function notInVar(a, b) { return a + b } var inVar = function doesThisWork(a, b) { return a + b } document.writeln('2 + 2 = ' + notInVar(2, 2)); document.writeln('3 + 3 = ' + inVar(3, 3)); document.writeln
function notInVar(a, b) {
return a + b
}
var inVar = function doesThisWork(a, b) {
return a + b
}
document.writeln('2 + 2 = ' + notInVar(2, 2));
document.writeln('3 + 3 = ' + inVar(3, 3));
document.writeln('4 + 4 = ' + doesThisWork(4, 4));
在Chrome中,前两个document.writelns按预期执行,然后我得到“uncaughtreferenceerror:does此工作未在Chrome中定义”
。为什么我不能调用第二个函数名为doesthisswork
?因此,第一个函数对象notInVar存储在哪里
因此,第一个函数对象notInVar存储在哪里
相当于
var notInVar = function (a, b) {
return a + b
}
在您的情况下,notInVar
存储在全局范围中
然后我在中得到“uncaughtreferenceerror:doesthisswork未定义”
铬
类似于
var inVar = function (a, b) {
return a + b
}
在功能外部访问它时
您不能通过
doesthisswork
访问函数,但必须通过inVar
以编写的方式访问函数,doesthisswork
仅在其内部可用。函数是对象。变量inVar
包含一个名为的函数对象,该函数对象执行此工作
inVar.name //=> "doesThisWork"
如果一个函数没有名字,它是匿名的
要调用存储在变量中的函数,可以使用变量名(对该对象的引用)。如果要在同一个函数内调用函数(对于递归),可以通过其名称调用它,在本例中,执行此工作
第二个定义称为a,并且由于该定义的性质,只能从函数体内部通过名称调用它:
inVar.name //=> "doesThisWork"
var inVar = function doesThisWork(a, b) {
return doesThisWork(a + b); // infinite recursion!
}
这可以用来在一个匿名函数中实现递归,而不必使用。函数是一个变量,变量的范围很重要。对于第二个函数,在全局范围内,其变量名为inVar。函数名不该工作在其自己的作用域内,对全局作用域不可见。所以你只能使用因瓦,而不能做这项工作。关于这一点,有很多方面:
第一:函数的名称将是本地的,因此您只能从本地调用相同的函数。如果(doesThisWork.caller!=doesThisWork)返回doesThisWork(a,b),则它在使用时可能会触发无限递归,除非像这样进行过滤if(doesThisWork.caller!=doesThisWork)代码>
第二,您正在为函数指定一个名称(不是将其作为匿名函数),而是为其容器指定一个本地名称
TL;DR=>跳转到分析以获得更清晰的想法
注意函数的声明方法之间的差异很有趣:
内联声明:
在分析时/运行时声明:
我的分析:这里的局部性是由于赋值造成的,因为当您在函数中声明函数时,该名称将在包含函数的局部使用,而不是在包含函数的外部使用,对于包含函数的变量也是如此,因为它包含函数及其名称。仍然可以在其作用域中使用包含函数的变量,因为它是容器函数的局部变量,容器函数是不同的作用域
*global这里指函数位置的全局,而不是文档的全局。因为它对其容器是局部的,但对同一容器中的其他对象是全局的。@stackErr:看起来不错。这是一个命名函数表达式。不确定,但我要说的是变量范围。。偶然检查一下,它在IE中“起作用”,因为IE坏了。:-)可选名称只能在函数内部使用,不能在函数外部使用。顺便说一句,ECMA参考用于,向下滚动到带有可选标识符的零件,它应该变得清晰。不太清楚。。。最接近的等价物是var foo=function foo(){}
,这样您仍然有一个名称可以显示在调用堆栈跟踪中。@elclanrs:我想我需要重写它。它类似于在函数外部访问它。谢谢你的指点,有什么问题吗way@KhanhTO实际上,当您从inVar访问doesThisWork时,实际上是在访问函数而不是doesThisWork,doesThisWork是包含它的变量(或对象)的局部变量,不能从外部调用。这同样适用于在另一个函数中声明的函数。这与Y组合子有什么关系?这不会让你像Y-Combinator那样做无限递归,如果你这么建议的话。@CrazyTrain Y-Combinator影响匿名递归;无限递归总是可能的:)使用Y-Combinator,您可以有无限递归,因为调用堆栈不会增长。为函数命名并不能阻止调用堆栈的增长。JavaScript函数不是尾部调用优化的。@CrazyTrain我现在明白你的意思了;它也与答案本身有点不相关,“无限递归”评论只是警告人们不要尝试代码而不知道他们在做什么:当然,我也认为递归是无限的,即使堆栈中断HEH。谢谢解释“函数名称的去向”。
var inVar = function doesThisWork(a, b) {
return doesThisWork(a + b); // infinite recursion!
}
var x = function fnName(){}; console.log(x.prototype); => fnName {} // but used locally to x
var x = function(){}; console.log(x.prototype); => Object {} // no local name, only global x
function fnName(){}; console.log(fnName.prototype); => fnName {} // global* and local name