Javascript 在全局对象中使用“this”

Mar*_*aio 1 javascript object this dom-events

'this' 关键字在全局对象中使用时指的是什么?

假设我们有:

  var SomeGlobalObject =
  {
     rendered: true,
     show: function()
     {
        /*
        I should use 'SomeGlobalObject.rendered' below, otherwise it 
        won't work when called from event scope.
        But it works when called from timer scope!!
        How can this be?
        */
        if(this.rendered)
           alert("hello");
     }
  }
Run Code Online (Sandbox Code Playgroud)

现在,如果我们在 HTML 页面中调用内联脚本:

SomeGlobalObject.show();
window.setTimeout("SomeGlobalObject.show()", 1000);
Run Code Online (Sandbox Code Playgroud)

一切正常。

但是如果我们做这样的事情:

AppendEvent(window, 'load', SomeGlobalObject.show);
Run Code Online (Sandbox Code Playgroud)

我们收到错误,因为this.rendered从事件范围调用时未定义。

  1. 你知道为什么会这样吗?
  2. 你能解释一下是否有另一种更聪明的方法来做到这一点,而不必每次都将“SomeGlobalObject.someProperty”重写到 SomeGlobalObject 代码中?

AppendEvent 只是一个简单的跨浏览器函数来追加一个事件,代码如下,但是为了回答上面的问题没有关系。

  function AppendEvent(html_element, event_name, event_function)
  {
        if(html_element.attachEvent) //IE
           return html_element.attachEvent("on" + event_name, event_function);
        else
           if(html_element.addEventListener) //FF
              html_element.addEventListener(event_name, event_function, false);
  }
Run Code Online (Sandbox Code Playgroud)

And*_*y E 5

当您引用作为对象方法的函数时,您将它与该对象分离,并且this不再是对该对象的引用。

最简单的解决方案是将其包装在匿名函数中:

AppendEvent(window, 'load', function () { SomeGlobalObject.show() } );
Run Code Online (Sandbox Code Playgroud)

bind在 ECMAScript 第 5 版实现中还有可用于函数的方法,它允许您执行此操作:

AppendEvent(window, 'load', SomeGlobalObject.show.bind(SomeGlobalObject, arg1, arg2));
Run Code Online (Sandbox Code Playgroud)

JS 框架 Prototype 也为当前的 JS 实现提供了这种方法。代码(感谢@bobince):

// From Prototype.js
if (!Function.prototype.bind) { // check if native implementation available
  Function.prototype.bind = function(){ 
    var fn = this, args = Array.prototype.slice.call(arguments),
        object = args.shift(); 
    return function(){ 
      return fn.apply(object, 
        args.concat(Array.prototype.slice.call(arguments))); 
    }; 
  };
}
Run Code Online (Sandbox Code Playgroud)

  • ...或者如果缺少,请自行添加。http://stackoverflow.com/questions/2025789/preserving-a-reference-to-this-in-javascript-prototype-functions/2025839#2025839 (2认同)