在JavaScript中处理范围的正确方法

时间:2016-07-23 08:32:14

标签: javascript function structure

我的代码示意性遵循以下模式。重要的是,在外部函数中声明了一个参数,稍后在内部函数中使用该参数。

function outer(){
  var parameter = 3;
  this.value = parameter;
  $("#something").on("click", function(target){
    target.value = parameter / 2;
  });
}

实际上,内部函数是相当多的而且相当冗长所以我希望将它们移出来以提高可读性,就像这样。

var parameter = 3;
function outer(){
  this.value = parameter;
  $("#something").on("click", inner);
}
function inner(target){
  target.value = parameter / 2;
}

然而,我注意到的是,由于JavaScript的范围范式,我不得不将参数声明移出外部函数,因此使其成为全局,这对我来说似乎是一个缺点。 (实际上,有许多参数被使用,因此直接传递它们会使目的失败。)

我无法确定哪种方法缺点较少。问题是,是否可以污染全球范围以获得可读性,或者它是否绝对禁止。

1 个答案:

答案 0 :(得分:4)

重新修改你的问题:

  

问题是,是否可以污染全球范围以获得可读性,或者它是否绝对禁止。

绝对禁止。全球命名空间已经远远受到污染。而且几乎从来没有任何理由这样做:相反,你可以污染使用包含所有代码的范围(近全局,如果你愿意的话)尽可能多:

(function() {
    // Our private scope
    var lots, of, vars, here;

    function outer() {
        // ...
    }
    function inner() {
        // ...
    }
})();

这至少可以使你的变量真正成为全局变量。

尽管如此,保持变量范围尽可能受限仍然是最好的。很酷的是,您可以根据需要重复上述操作,为公共代码创建小范围,将它们嵌套为matryoshka

问题修订前的早期答案:

如果问题是"什么更好,"答案是:都没有。他们每个人都有自己的位置,对不同的事情都很有用。

如果您正在寻找第三种解决方案,您可以使用部分应用程序(有时称为currying,尽管纯粹主义者有问题)。 JavaScript没有内置的部分应用程序功能,不会与this混淆,但您可以轻松添加一个:

(function() {
    // Note use of micro-scope here. It's a micro-optimiziation to avoid
    // looping up `slice` every time we need it. Mostly it's a justification
    // for demonstrating a micro-scope. :-)
    var slice = Array.prototype.slice;
    Object.defineProperty(Function.prototype, "curry", { // purists: sorry ;-)
      value: function() {
        var f = this;
        var args = slice.call(arguments, 0);
        return function() {
          return f.apply(this, args.concat(slice.call(arguments)));
        };
      }
    });
})();

然后

function outer(){
  var parameter = 3;
  this.value = parameter;
  $("#something").on("click", inner.curry(parameter));
}
function inner(parameter, target){
  target.value = parameter / 2;
}

您已经提到过这些可能很多;如果是这样,你可能会考虑一个具有属性的对象,所以你只是讨论对象引用而不是很多离散变量。

示例:



    (function() {
      // Note use of micro-scope here. It's a micro-optimiziation to avoid
      // looping up `slice` every time we need it. Mostly it's a justification
      // for demonstrating a micro-scope. :-)
      var slice = Array.prototype.slice;
      Object.defineProperty(Function.prototype, "curry", { // purists: sorry ;-)
        value: function() {
          var f = this;
          var args = slice.call(arguments, 0);
          return function() {
            return f.apply(this, args.concat(slice.call(arguments)));
          };
        }
      });
    })();

    function outer() {
      var parameter = 3;
      setTimeout(inner.curry(parameter));
    }

    function inner(parameter) {
      console.log("Got parameter = " + parameter);
    }

    outer();