【问题标题】:Javascript scope issue when function from array数组中的函数时的Javascript范围问题
【发布时间】:2012-11-01 10:45:39
【问题描述】:

作为我正在构建的 Web 应用程序的一部分,可以同时从服务器输入多个命令。

当这些命令被处理时,数据往往会被更新,然后可能会发生相当大量的页面 HTML 生成。

当多个类似的命令进来的那一刻,程序会处理数据,然后每次都重新生成部分页面。这会导致大量的处理时间浪费。

因此,我正在尝试创建一个调用堆栈,因此在处理命令时,它会查看命令触发的函数是否在堆栈中,如果未找到,则添加它。


我的问题是将调用堆栈中的被调用函数保持在正确的范围内,同时还能消除重复项。

基本代码:

var tools = {
  functions:{
    function1: function(){
      return this;
    },
    function2: function(){
    }
  },
  unique: function(arr){
    var returnArr=[],
        x, i;

    for (x=0; x<arr.length; x++){
      for (i=(x+1); i<arr.length; i++){
        if (arr[x]===arr[i]){
          arr.splice(i, 1);
        }
      }
      returnArr.push(arr[x]);
    }

    return returnArr;
  }
}

示例 1:

var callstack=[tools.functions.function1, tools.functions.function1];

callstack = tools.unique(callstack);

for (var x=0; x<callstack.length; x++){
  console.log(callstack[x](), "should equal tools.functions");
}

这会失败,因为 "this" 将返回 [function()]


示例 2:

var callstack=[
  (function(){return tools.functions.function1()}),
  (function(){return tools.functions.function1()})
];

callstack = tools.unique(callstack);

for (var x=0; x<callstack.length; x++){
  console.log(callstack[x](), "should equal tools.functions");
}

这会失败,因为您无法确保函数是唯一的,所以它仍然会运行该函数两次。


这可以通过使用两个数组来解决(一个跟踪函数的名称,一个保存封装的函数)并使它们保持同步,但我不禁觉得必须有一个更清洁的使用 .call 的方式,但我看不到它。

JSFiddle:http://jsfiddle.net/Kj6E8/

【问题讨论】:

    标签: javascript scope call apply


    【解决方案1】:

    一般来说,以您需要的方式保留this 的值是不可能的。一旦将这些函数推入数组,这些函数曾经驻留的对象就会丢失。

    如果您只在单个对象上调用函数,则需要以某种方式将您的函数绑定到该对象。有很多方法可以做到这一点,例如,您可以传递对象以将这些函数绑定到您的唯一函数中。

    http://jsfiddle.net/8WAZb/1/

    var tools = {
      functions:{
        function1: function(){
          return this;
        },
        function2: function(){
        }
      },
      unique: function(arr, o){
        var returnArr=[],
            x, i;
    
        for (x=0; x<arr.length; x++){
          for (i=(x+1); i<arr.length; i++){
            if (arr[x]===arr[i]){
              arr.splice(i, 1);
            }
          }
            returnArr.push(this.bind(arr[x], o));
        }
    
        return returnArr;
      },
      bind: function(f, o) {
          return function () {
              return f.apply(o, arguments);
          }
      }
    }
    
    console.info("Example 1:");
    var callstack=[tools.functions.function1, tools.functions.function1];
    callstack = tools.unique(callstack, tools.functions);
    console.log("Callstack:",callstack);
    for (var x=0; x<callstack.length; x++){
      console.log(callstack[x](), "should equal tools.functions");
    }
    

    您推断this 值的方式和时间实际上取决于您何时将该对象包含在范围内。假设您更有可能在调用堆栈创建阶段将该对象放在范围内,并且可能不一定在您希望调用调用堆栈中的函数的时候。如果是这样的话,尽早绑定(即在减少到一个唯一的调用堆栈期间)似乎是一个明智的选择。

    【讨论】:

      【解决方案2】:

      在 JavaScript 中,this 是从外部调用者定义的,所以当你这样做时:

      callstack[x]()
      

      您将window 范围带入函数。如果你想引入tools.functions 对象,你需要这样做:

      callstack[x].call(tools.functions);
      

      http://jsfiddle.net/Yv4sM/

      【讨论】:

      • 谢谢。不幸的是,并非我的所有函数都位于同一个命名空间中,所以我不能只在最后推动单个调用。可能我可以解决像这样的问题jsfiddle.net/Kj6E8/1 不幸的是,我认为这可能是我能得到的最干净的,因为我似乎无法找到一种方法来找到函数的父对象而不遍历所有内容 =[
      猜你喜欢
      • 2011-11-13
      • 1970-01-01
      • 2013-05-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多