javascript范围与setTimeout和bind的陷阱

时间:2017-05-18 15:09:57

标签: javascript scope settimeout

对于下面的代码,我期望控制台2和3使用“Jupiter”,但是将一个绑定到全局窗口对象,即使我传递了不同的上下文。

function otherScope () {
  this.sectionHeight = "Jupiter"
}

(function () {
    var sectionHeight = "Mars";
    (function () {
      setTimeout(function () {
        console.log('console 1', sectionHeight)
      })
    }())
}())

window.sectionHeight = "cool!";

(function () {
  setTimeout(function () {
    console.log('console 2', sectionHeight)
  })
}.bind(otherScope)())


setTimeout(function () {
  console.log('console 3', sectionHeight)
}.bind(otherScope))


setTimeout(function () {
  console.log('console 4', sectionHeight)
})

3 个答案:

答案 0 :(得分:4)

Te otherScope是一个函数,不是具有属性的Object。你必须这样做new。所以:

var x = new otherScope();
x.sectionHeight;

接下来,其范围仅达到当前范围。 setTimeout创建一个新范围。因此我们需要做另一个绑定。或者在setTimeout之外的第一个范围内创建一个变量。

一些例子(范围内的变量):

(function () {
  var theScope = this;
  setTimeout(function () {
    console.log('console 2', theScope.sectionHeight)
  });
}.bind(new otherScope())())

一些例子(另一个绑定):

(function () {
  setTimeout(function () {
    console.log('console 2', this.sectionHeight)
  }.bind(this)); // Pass the context to the new scope
}.bind(new otherScope())())

答案 1 :(得分:2)

bind为调用它的函数设置this的值(我将其称为x)。

它没有:

  • 即使y y
  • 调用,也会影响其他功能(x
  • 影响x范围内的变量或x调用的任何函数。

无法更改函数所在的范围。这仅取决于声明的位置。

答案 2 :(得分:0)

Niels使用otherScope作为构造函数new,这是针对您的特定问题的绝佳解决方案。但请注意,JavaScript是一种非常灵活的语言,因此有许多可能的替代方案......

你可以:

  1. 添加"静态"拥有otherScope
  2. 的财产
  3. 将属性添加到otherScope
  4. 的原型中
  5. otherScope
  6. 中返回对象文字

    静态属性

    
    
    function otherScope () {}
    otherScope.sectionHeight = "Jupiter";
    
    (function () {
        var sectionHeight = "Mars";
        (function () {
          setTimeout(function () {
            console.log('console 1', sectionHeight);
          });
        }());
    }());
    
    window.sectionHeight = "cool!";
    
    (function () {
      var that = this;
      setTimeout(function () {
        console.log('console 2', that.sectionHeight);
      });
    }.bind(otherScope)());
    
    
    setTimeout(function () {
      console.log('console 3', this.sectionHeight);
    }.bind(otherScope));
    
    
    setTimeout(function () {
      console.log('console 4', sectionHeight);
    });
    
    
    

    原型属性

    
    
    function otherScope () {}
    otherScope.prototype.sectionHeight = "Jupiter";
    
    (function () {
        var sectionHeight = "Mars";
        (function () {
          setTimeout(function () {
            console.log('console 1', sectionHeight);
          });
        }());
    }());
    
    window.sectionHeight = "cool!";
    
    (function () {
      var that = this;
      setTimeout(function () {
        console.log('console 2', that.sectionHeight);
      });
    }.bind(otherScope.prototype)());
    
    
    setTimeout(function () {
      console.log('console 3', this.sectionHeight);
    }.bind(otherScope.prototype));
    
    
    setTimeout(function () {
      console.log('console 4', sectionHeight);
    });
    
    
    

    对象文字

    
    
    function otherScope () {
      return {sectionHeight: "Jupiter"};
    }
    
    (function () {
        var sectionHeight = "Mars";
        (function () {
          setTimeout(function () {
            console.log('console 1', sectionHeight);
          });
        }());
    }());
    
    window.sectionHeight = "cool!";
    
    (function () {
      var that = this;
      setTimeout(function () {
        console.log('console 2', that.sectionHeight);
      });
    }.bind(otherScope())());
    
    
    setTimeout(function () {
      console.log('console 3', this.sectionHeight);
    }.bind(otherScope()));
    
    
    setTimeout(function () {
      console.log('console 4', sectionHeight);
    });