这会在浏览器之间返回不同

时间:2014-08-21 08:06:57

标签: javascript internet-explorer coffeescript scope requirejs

我偶然发现了一个我无法理解的问题,我希望这里的一些聪明人可能会启发我: - )

使用RequireJs的以下CoffeeScript给我一个范围问题。它可以与我们的老朋友Internet Explorer(即使是最新版本)中的任何其他浏览器完美配合。

问题是this.stop(),或者更确切地说只是this在Internet Explorer中为window提供了window.stop()以及在其他浏览器中所有代码都存在的对象。

因此Internet Explorer尝试stop(),这显然不会起作用。虽然其他浏览器只是在范围内运行.push()方法。这是为什么?

是否与在Internet Explorer中以其他方式工作的Array原型函数define ['require', 'cs!scroller', 'cs!router', 'jquery', 'cs!menu', 'cs!magicbox', 'newsflash', 'swiper', 'time', 'cs!ads'], (require, Scroller, Router, $, Menu, Magicbox, Newsflash, Swiper, Time) -> start: -> Router.addRouterEvents() window.Looper = [] window.Looper.push () -> [this.stop(), Router.start(), Scroller.start(), Newsflash(), Swiper(), Time()] for func in window.Looper func() stop: -> $('*').off() 有关?或者它只是一个错误?请赐教?

// Generated by CoffeeScript 1.7.1
(function() {
  define(['require', 'cs!scroller', 'cs!router', 'jquery', 'cs!menu', 'cs!magicbox', 'newsflash', 'swiper', 'time', 'cs!ads'], function(require, Scroller, Router, $, Menu, Magicbox, Newsflash, Swiper, Time) {
    return {
      start: function() {
        var func, _i, _len, _ref, _results;
        Router.addRouterEvents();
        window.Looper = [];
        window.Looper.push(function() {
          return [this.stop(), Router.start(), Scroller.start(), Newsflash(), Swiper(), Time()];
        });
        _ref = window.Looper;
        _results = [];
        for (_i = 0, _len = _ref.length; _i < _len; _i++) {
          func = _ref[_i];
          _results.push(func());
        }
        return _results;
      },
      stop: function() {
        return $('*').off();
      }
    };
  });

}).call(this);

以下是编译为JavaScript的相同代码(对于我们熟悉的较少的CoffeeScript,因为除了问题在于CoffeeScript本身,我不会这样做):

{{1}}

2 个答案:

答案 0 :(得分:2)

我没有运行你的代码,但我打赌你在所有平台上确实存在相同的基本问题。当您执行Looper数组上的功能时,它们始终会window作为this的值。

问题是window在多个平台上有stop方法但在IE上没有。 (This是我这样说的来源。)因此,当您在IE上运行时,您会立即收到错误消息。在其他平台上,您可以拨打window.stop(),这不是您想要的。对于踢,我在Chrome中运行了这个,没有错误:

(function () { this.stop() })()

您可以使用thisbind设置为所需的值。它在JavaScript中看起来像这样:

window.Looper.push(function() {
    return [this.stop(), Router.start(), Scroller.start(), Newsflash(), Swiper(), Time()];
}.bind(this));

(注意匿名函数末尾的.bind(this)。)

我建议您在"use strict";的匿名函数的开头添加define。它使得JavaScript在更健全的语义下运行,而不是没有它,并且这有助于在此找到问题,因为this应该是undefined而不是设置为window

答案 1 :(得分:1)

由此产生的JS让我觉得有点奇怪。从你的CoffeeScript看起来你正试图设置window.Looper作为一个函数数组,你循环并调用每个函数你去?但是JavaScript给了我们洞察力,实际上变量_i永远不会超过0,因为它循环遍历数组窗口.Looper,它包含一个单独的项目,这是你在这里推送它的函数:

window.Looper.push(function() {
   return [...];
});

然后在此执行此单一功能:

_results.push(func());

然后执行此功能:

function() {
      return [this.stop(), Router.start(), Scroller.start(), Newsflash(), Swiper(), Time()];
}

返回在添加到数组时执行的函数数组。所以你的循环并没有真正实现任何目标,因为在这个设置中你需要做的就是忘记_i循环,而是调用:

window.Looper[0]()

执行函数数组中的所有内容。

所以这个函数调用序列看起来很复杂,我相信你会遇到范围问题。我不完全确定,但鉴于this.stop()正在执行window.Looper0返回一个匿名函数,我原本认为范围将成为所有浏览器的窗口 - 我很困惑至于这段代码是如何工作的! EG,这是一个简化版本,显示了这个&#39;的价值。当你调用this.stop()确实是窗口时:

http://repl.it/XPF/1

可能需要/ js正在做一些魔术让它工作,我无法在repl.it片段中模拟。无论哪种方式,我认为解决方案是JavaScript将简化为简化:

window.Looper = [this.stop, Router.start, Scroller.start, Newsflash, Swiper, Time]

即,可以循环和调用的函数引用数组。这是一个例子,显示了没有require.js的这个概念和一个Router.start的存根:

http://repl.it/XPF

我认为相应的咖啡脚本将是:

define ['require', 'cs!scroller', 'cs!router', 'jquery', 'cs!menu', 'cs!magicbox', 'newsflash', 'swiper', 'time', 'cs!ads'], (require, Scroller, Router, $, Menu, Magicbox, Newsflash, Swiper, Time) ->

  start: ->

    Router.addRouterEvents()

    // Push funcs into the array, in case there is already something there (see comments)
    // Probably a nicer way of doing this in CoffeeScript
    // in JS I'd do window.Looper.push.apply(window.Looper, [func, func])
    window.Looper.push(this.stop)
    window.Looper.push(Router.start)
    window.Looper.push(Scroller.start)
    window.Looper.push(Newsflash)
    window.Looper.push(Swiper)
    window.Looper.push(Time)

    for func in window.Looper
      func()

  stop: ->
    $('*').off()