函数级作用域的优缺点(特别是在Javascript中)
与Java等语言中的块级范围相比,Javascript中的函数级范围有哪些优点和缺点函数级作用域的优缺点(特别是在Javascript中),javascript,Javascript,与Java等语言中的块级范围相比,Javascript中的函数级范围有哪些优点和缺点 我希望看到一些函数级作用域使用的示例,这些示例使用块级作用域将更难或不可能实现。首先想到的示例是:如果使用块级作用域实现,JavaScript处理函数级作用域的成本将高得多 当您在JavaScript中输入一个函数时,会分配一个对象(好吧,一对,但我们将重点关注一个),该对象最终成为“变量对象”——也就是说,该函数调用的所有参数和局部变量都保存在该对象中(作为属性)。闭包实际使用的是这个对象(不仅仅是它似乎使用
我希望看到一些函数级作用域使用的示例,这些示例使用块级作用域将更难或不可能实现。首先想到的示例是:如果使用块级作用域实现,JavaScript处理函数级作用域的成本将高得多 当您在JavaScript中输入一个函数时,会分配一个对象(好吧,一对,但我们将重点关注一个),该对象最终成为“变量对象”——也就是说,该函数调用的所有参数和局部变量都保存在该对象中(作为属性)。闭包实际使用的是这个对象(不仅仅是它似乎使用的“符号”;这是一个常见的误解)。这些对象串在一个称为作用域链的链中,用于解析非限定符号
想象一下,如果每个块都引入了新的作用域,那么成本会高出多少。没有什么你做不到的——用块级作用域模拟函数级作用域并不难,反之亦然 但是,条件函数声明会更加笨拙:
if (console && console.log) {
function debug(msg) { console.log(msg); }
} else {
function debug(msg) { alert(msg); }
}
debug('foo'); // does not work with block scope
我想看看函数级作用域使用的例子,使用块级作用域更难或不可能实现
也许这听起来很明显,但您可以在函数级范围内实现递归,这通常很有用,例如:
var x = 5; // global scope
(function (y) { // y - locally scoped variable on each execution
y && arguments.callee(--y); // recursion!
console.log(y);
})(x);
这在块级范围内几乎不可能实现
在上面的示例中,函数将首先执行,并将外部x
变量的值传递给它,在调用函数之前,将设置一个新的执行上下文,该上下文初始化一个新的词法范围,其中y
形式参数绑定到它
之后,再次执行函数表达式-如果
y
不是0
-每次执行时初始化一个全新的词法作用域。您的意思是如果使用块级作用域实现。@Peter:Crikey,现在手指滑倒了。。。谢谢这实际上从未被标准化过,它只在Mozilla实现中起作用,因为它们定义了一个函数语句,这在ECMAScript规范中是不存在的。其他实现将只接受最后一个FunctionDeclaration
,尽管该代码应该导致一个SyntaxError
,因为没有语法产品可以接受块内的FD。@CMS:确实如此。Tgr:应该使用函数表达式有条件地分配函数。请参阅@CMS:“…因为没有语法产品可以接受FD的内部块。”哇,这部分我不知道。我知道FunctionDeclaration
将被处理,不管它在函数中的什么位置(例如,不是有条件的),但我没有意识到语法不支持它。正如你所指出的,这当然是个坏主意。正如Marcel所说,使用函数表达式(正如Marcel在kangax的文章中指出的,除非你愿意,否则使用匿名表达式)。@T.J.,是的,大量实现支持一些非官方的语法扩展,另一个例子是文本:08
或09
,它们是无效的NumericLiteral
,因为DecimalIntegerLiteral
不能以0
开头(当然,除非0
值本身),并且它们与OctalIntegerLiteral
语法:0 OctalDigit
不匹配,因为显然,一个八进制数字只能是0
中的一个,1
,2
,3
,4
,5
,6
和7
。这些文本应该导致一个语法错误
,但在所有实现中,前导零都被忽略,08==8
,09==9
。