哪种设计模式利用了JavaScript的提升行为?

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)

这基本上意味着它是什么样子:myCoolJSmyCoolJS,如果它不存在,或者如果没有一个新的对象.第二个myCoolJS不会抛出一个ReferenceErrorif myCoolJS尚未存在,因为这个变量声明被提升了.

这样可以避免我们进行尴尬的typeof myCoolJS != 'undefined'检查.

功能提升

将多个脚本合并为一个时,函数提升特别有用.例如,我已经创建了CommonJS模块的轻量级构建时实现.这提供相同的module,requireexports功能,在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)

随着块作用域,你就必须添加另一行申报valueif.

公平地说,这段代码因功能范围而不是吊装而起作用.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.我从未在其他地方听说过,但这并不一定意味着它在其他语言中不存在.

  • 这些都是深思熟虑的评论,但我认为你实际上并没有提供一个用于吊装的用例.这只是你心中的风格问题吗? (3认同)

Šim*_*das 9

该文中的前两个例子写得很糟糕.糟糕的代码显然会导致错误和混乱.让我给你这些例子的重构版本.你会发现这里没有混淆......

示例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".明显.这里也没有混淆.

  • @beldaz在评估函数体的代码(任何代码)之前,变量声明语句的变量名称绑定到词法环境(当前执行上下文)*.这个过程应该由源代码反映出来.因此,变量声明语句应该是函数体的第一个语句,并且不应该在它们之前放置其他语句.在代码"中间"放置变量声明语句与底层进程不对应,这种断开可能导致错误(如OP的代码清楚地显示). (4认同)
  • 这个例子是关于功能范围,而不是关于提升. (2认同)

Fir*_*aze 6

"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的提升行为?"答案:没有.


Mik*_*sen 5

我认为提升有用的一个领域是由于函数被视为第一类对象.例如:

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)

我想他们可能只有悬挂的功能对象,但我认为这与功能应该被视为语言中的一等公民的哲学不一致.

  • 你的最后一个例子是错误*带*吊装 - 声明被悬挂,而不是分配.当你试图调用它时,`b`将是`undefined`. (2认同)