Dav*_*ers 44 javascript scope hoisting
Ben Cherry的优秀文章充分阐述了JavaScript中的提升.然而,我的问题是,我不能为这个臭名昭着的混淆犯罪者设想一个用例.请解释是否存在实际利用此语言功能的设计模式.
其次,是JavaScript独有的范围提升?
更新 ---我正在为满足我的好奇心的答案添加赏金:哪种设计模式实际上利用了JavaScript的提升行为?我理解为什么 JavaScript支持提升,但我想知道如何利用这个功能.
Dag*_*bit 19
吊装最简单的用途之一是可变吊装.如果我们没有变量提升,这将抛出ReferenceError:
var bar = foo;
var foo;
Run Code Online (Sandbox Code Playgroud)
这似乎没有立即有用,但它允许我们做这样的事情:
var myCoolJS = myCoolJS || {};
Run Code Online (Sandbox Code Playgroud)
这基本上意味着它是什么样子:myCoolJS是myCoolJS,如果它不存在,或者如果没有一个新的对象.第二个myCoolJS不会抛出一个ReferenceErrorif myCoolJS尚未存在,因为这个变量声明被提升了.
这样可以避免我们进行尴尬的typeof myCoolJS != 'undefined'检查.
将多个脚本合并为一个时,函数提升特别有用.例如,我已经创建了CommonJS模块的轻量级构建时实现.这提供相同的module,require和exports功能,在node.js中发现 我构建了工具,允许所需的模块由多个文件组成.例如,require('/foo')可能导致由两个文件foo.js("正文文件")和foo.h.js("头文件")组成的模块.
这允许"正文文件"不知道CommonJS模块环境提供的自由变量; 所有这些都在标题中处理.这使得代码可以重复使用,并且无需构建即可轻松测试.但是,由于标题预先附加到正文,我们利用正文文件中的函数提升来允许标题中的导出.例如:
// dom.h.js
var util = require('util').util;
exports.css = css; // we can do this because "css" is hoisted from below
// ... other exports ...
Run Code Online (Sandbox Code Playgroud)
...
// dom.js
function css(){}; // this would normally just be an object.
css.hasClass = function(element) { ... };
css.addClass = function(element) { ... };
// ...other code...
Run Code Online (Sandbox Code Playgroud)
Jor*_*ner 15
这是一个用于吊装的用途:
(function() {
var factorial = function(n) {
if(n == 0)
return 1;
return n * factorial(n - 1);
};
})();
Run Code Online (Sandbox Code Playgroud)
没有提升,这将无法编译,因为factorial在函数文字中不存在.您必须单独声明变量或使用命名函数.
JavaScript还允许以下代码:
var test = function(b) {
if(b) {
var value = 2;
} else {
var value = 5;
}
console.log(value);
};
Run Code Online (Sandbox Code Playgroud)
随着块作用域,你就必须添加另一行申报value前if.
公平地说,这段代码因功能范围而不是吊装而起作用.JavaScript可能没有提升功能范围.Ruby更好地处理这个问题:Ruby有变量的方法范围,但是在设置变量之前变量不存在:
def test(b)
# unlike JavaScript, value is not accessible here
if b
value = 2
else
value = 5
end
puts value
end
Run Code Online (Sandbox Code Playgroud)
ale*_*lex 11
JavaScript没有块作用域(let现在让我们忘记),因此任何变量声明都声明整个函数,JavaScript 确实具有作用域.
如果您这样考虑,JavaScript提升可能会更有意义.
如果你还记得提升,它不应该是错误和混乱的根源.这只是你必须理解和记住的那些怪癖之一.
我不确定吊装是否仅限于JavaScript.我从未在其他地方听说过,但这并不一定意味着它在其他语言中不存在.
该文中的前两个例子写得很糟糕.糟糕的代码显然会导致错误和混乱.让我给你这些例子的重构版本.你会发现这里没有混淆......
示例1 - 原始代码
var foo = 1;
function bar() {
if (!foo) {
var foo = 10;
}
alert(foo);
}
bar();
Run Code Online (Sandbox Code Playgroud)
示例1 - 重构代码(删除混淆)
var foo = 1;
function bar() {
var foo;
if ( !foo ) {
foo = 10;
}
alert( foo );
}
bar();
Run Code Online (Sandbox Code Playgroud)
警报显示"10",很明显为什么.这里没有混乱.
示例2 - 原始代码
var a = 1;
function b() {
a = 10;
return;
function a() {}
}
b();
alert(a);
Run Code Online (Sandbox Code Playgroud)
示例2 - 重构代码(删除混淆)
var a = 1;
function b() {
var a = function () {};
a = 10;
return;
}
b();
alert( a );
Run Code Online (Sandbox Code Playgroud)
警报显示"1".明显.这里也没有混淆.
"hoisting"不是ECMAScript标准的一部分,但它确实说函数内部的变量是在函数的开头声明的,无论函数在代码中的位置如何.
例
(function() {
alert(myvar); // undefined
var myvar = 'local value';
})();
Run Code Online (Sandbox Code Playgroud)
内部Javascript会在警报之前声明myvar,显示警报,然后将myvar分配给"本地值".
所以Javascript会将代码插入:
(function() {
var myvar;
alert(myvar); // undefined
myvar = 'local value';
})();
Run Code Online (Sandbox Code Playgroud)
这就是为什么"Java the Good parts"有一个指导原则,你应该在函数的顶部声明变量.
资料来源:http://net.tutsplus.com/tutorials/javascript-ajax/quick-tip-javascript-hoisting-explained/
"请解释是否存在实际利用此语言功能的设计模式." "hoisting"不是一个特性,而是Javascript解释器如何构造代码的结果,因为该语言使用了函数作用域.
"哪种设计模式实际上利用了JavaScript的提升行为?"答案:没有.
我认为提升有用的一个领域是由于函数被视为第一类对象.例如:
function foo()
{
function a()
{
//...
}
function b()
{
//...
}
}
Run Code Online (Sandbox Code Playgroud)
也可以写成:
function foo()
{
var a = function ()
{
//...
}
var b = function ()
{
//...
}
}
Run Code Online (Sandbox Code Playgroud)
如果没有提升,以下内容将导致错误:
function foo()
{
var a = function ()
{
b();
}
a(); //Error in function since b is not yet defined
var b = function ()
{
//...
}
}
Run Code Online (Sandbox Code Playgroud)
我想他们可能只有悬挂的功能对象,但我认为这与功能应该被视为语言中的一等公民的哲学不一致.