Javascript范围丢失问题

时间:2011-09-08 11:34:28

标签: javascript prototypejs

这是我的Dropdown菜单类。并且在hide方法中回调函数afterFinsih 放弃了班级的范围。我不想宣布全球变通。有没有更好的解决方案?

  var DropMenu = Class.create({ 
    // Class properties.
    speed: 0.4,
    delay: 0,
    active_submenu: null,

    initialize: function() {
      $$("li.drop_down_element").invoke('observe', 'mouseenter', this.mouseOver.bind(this));
      $$("li.drop_down_element").invoke('observe', 'mouseleave', this.mouseOut.bind(this));
    },

    show: function(elem, speed) {
        new Effect.BlindDown(elem, {duration: speed, queue: {position: 'end', scope: elem.identify(), limit:13}});
    },

    hide: function(elem, speed) {

      if(elem.visible())
      {
        new Effect.BlindUp(elem, {duration: speed, queue: {position: 'end', scope: elem.identify(), limit: 13}, afterFinish: function(scope) { console.info(scope)}(this)});
      }
    },

    mouseOver: function(event) {
      var element = event.element(), 
          submenu = element.getElementsByClassName('submenu_element')[0],
          width   = element.getWidth();
      if(submenu)
      {
        submenu.setStyle({minWidth: width + 'px'})
                this.active_submenu = submenu;
        this.show(submenu, this.speed);        
      }
      if(!this.iefix && Prototype.Browser.IE) 
      {
        new Insertion.After(submenu, 
        '<iframe id="dropdown_iefix" '+
        'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +
        'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
        this.iefix = $(submenu.id+'_iefix');
      }

      //if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);

    },

    mouseOut: function(event) {

      var submenu = this.active_submenu;


      if (submenu)
      {
        this.hide.delay(this.delay, submenu, this.speed);
      }
    },

    fixIEOverlapping: function() {
        Position.clone(this.active_submenu, this.iefix, {setTop:(!this.active_submenu.style.height)});
        this.iefix.style.zIndex = 700;
        this.iefix.style.border = '2px solid #000';
        this.active_submenu.style.zIndex = 999;
        Element.show(this.iefix);
    }

  });
  document.observe('dom:loaded', function() { new DropMenu(); });

1 个答案:

答案 0 :(得分:1)

你可以这样做:

if(elem.visible())
{
    var that = this;
    new Effect.BlindUp(elem, {
        duration: speed,
        queue: {position: 'end', scope: elem.identify(), limit: 13},
        afterFinish: function() { console.info(that); }
    });
}

......但你可能不喜欢这样。有些浏览器支持Function.prototype.bind,它允许您创建一个绑定到所需范围的函数,例如:

if(elem.visible())
{
    var that = this;
    new Effect.BlindUp(elem, {
        duration: speed,
        queue: {position: 'end', scope: elem.identify(), limit: 13},
        afterFinish: (function() { console.info(this); }).bind(this);
    });
}

如果您没有Function.prototype.bind,则可以使用此代码段(stolen from MDN)来定义它(您声明您正在使用Prototype,它应该已经拥有它):

if (!Function.prototype.bind) {  

  Function.prototype.bind = function (oThis) {  

    if (typeof this !== "function") // closest thing possible to the ECMAScript 5 internal IsCallable function  
      throw new TypeError("Function.prototype.bind - what is trying to be fBound is not callable");  

    var aArgs = Array.prototype.slice.call(arguments, 1),   
        fToBind = this,   
        fNOP = function () {},  
        fBound = function () {  
          return fToBind.apply(this instanceof fNOP ? this : oThis || window, aArgs.concat(Array.prototype.slice.call(arguments)));      
        };  

    fNOP.prototype = this.prototype;  
    fBound.prototype = new fNOP();  

    return fBound;  

  };  

}