一道经典JS题(关于this)

Posted 郑兴鹏

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一道经典JS题(关于this)相关的知识,希望对你有一定的参考价值。

项目中碰到的问题,以前也碰到过,没有重视,现记录如下。

复制代码<input type=\'button\' value=\'click me\' id=\'btn\' />
<script>
  var num = 0;

  var obj = {
    num: 1,

    fn: function() {
      console.log(this.num);
    },

    init: function() {
      setTimeout(this.fn, 0);

      document.getElementById(\'btn\').addEventListener(\'click\', this.fn, false);
    }
  };

  obj.init();
</script>

输出啥?点击 button 后输出啥?

解决类似的问题其实很简单,只需要牢记下面一句话:

除了 DOM 的事件回调或者提供了执行上下文(call、apply、bind)的情况,函数正常被调用(不带new)时,里面的 this 指向的是全局作用域。

先看第一处,其实可以改写成这样:

复制代码setTimeout(function() {
  console.log(this.num);
}, 0);

0ms后 函数正常被调用,里面的 this 指向全局作用域 window,所以输出即为 window.num,即为代码最开始定义的 num=0。

再看第二处,可以改写成这样:

复制代码document.getElementById(\'btn\').addEventListener(\'click\', function() {
  console.log(this.num);
}, false);

click 后触发一个回调函数,属于 DOM事件回调DOM 事件回调中的 this 指向该 DOM 元素。所以输出 this.num 即为 document.getElementById(\'btn\').num,为 undefined。

如何能让 click 事件后输出 1?因为这种需求在生产中很常见,绑定各种事件,回调已经定义的对象方法。很明显,归根结底需要改变函数中 this 指向。

方法一:

再加一层匿名函数,使得 fn 被 obj 调用:

复制代码var that = this;
document.getElementById(\'btn\').addEventListener(\'click\', function() {
  that.fn();
}, false);

方法二:

用 bind 改变 this 指向:

复制代码// 兼容IE
Function.prototype.bind = Function.prototype.bind || function(context) {
  var that = this;
  return function() {
    return that.apply(context, arguments);
  }
}

document.getElementById(\'btn\').addEventListener(\'click\', this.fn.bind(this), false);

以上是关于一道经典JS题(关于this)的主要内容,如果未能解决你的问题,请参考以下文章

一道关于JS作用域的面试题

一道经典面试题:字符串在Java中如何通过“引用”传递

几个关于js数组方法reduce的经典片段

关于js原型的面试题

关于js原型的面试题

几个关于js数组方法reduce的经典片段