关于this在浏览器中的指向

代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <div id="div0"></div>
</body>
<script>
  window.id = 'window';
  document.getElementById('div0').onclick = function(){
    alert(this.id);
    var callback = function(){
      alert(this.id)
    }
    callback();
  };
</script>
</html>

第一个输出"div0"可以理解很正常,为何第二个输出的是"window",callback是内部的函数他应该和外部的this都隐式调用指向div0,为何外部指向div0,内部指向window?
于是尝试命令行运行:

window.name = "window"
var text = function(){
  name = "text";
  alert(this.name);
  var callback = function(){
    alert(this.name)
  }
  callback()
}
text()

结果输出两次"text"
两者矛盾了吧,已晕望大神指点

阅读 4.2k
5 个回答
window.name = "window";
var text = function() {
    // name 没有用 var(或者 let、const)限定,是全局变量,即 window.name
    name = "text";

    // 参考下面 ①
    alert(this.name);

    var callback = function() {
        // 这个 this 参考 ②
        alert(this.name);
    };

    // ② 非对象方法方式调用,里面的 this 是全局对象,即 window
    callback();
};

// ① 非对象方法方式调用,text() 内部的 this 是全局对象,即 window
text();

所以自始至终你都是在操作同一个 name,即 window.name。如果想要理解 this,可以改一下代码

window.name= "window";

var obj = {
    text: function() {
        // 这两个 this 指的 obj,参考 ①
        this.name = "text";
        alert(this.name);

        // callback 内部的 this 参考 ②
        // 为了使用这里的 this,即 obj,可以用一个局部变量缓存
        var _this = this;
        var callback = function() {
            // 输出 widnow.name
            alert(this.name);

            // 输出 obj.name
            alert(_this.name);
        };

        // ② 对方法调用,callback() 内部的 this 是全局对象,即 window
        callback();
    }
};

// ① 方法调用,text 内部的 this 是 obj
obj.text();

// 这里的 obj.name 已经在 obj.text() 中赋值为 "text" 了
alert(obj.name);

补充一下

上面都是用的 es5 语法,如果用 es6 的箭头函数,或者说 Lambda 语法,就不需要缓存 _this

现在不是所有浏览器都支持 es6 语法,所以实际使用的过程中一般需要通过 babel 之类的工具编译成 es5。这里提出来只是顺着这个问题的知识点,多一个参考答案。

var obj = {
    text() {
        this.name = "text";
        var callback = () => {
            // Lambda 不改变作用域,这里的 this 就是 obj
            // this.name 就是 "text"
            alert(this.name);
        };
    }
};
obj.text();

我觉得 callback 又不是外部那个function的属性,所以callback里的this不会指向到外面那个function那边去。

至于为什么第二个例子都是text呢???

亲,里面的name忘了var了,没var会被当成全局,不信你再试试window.name看还是不是"window"

你描述的两种情况都可以佐证第一个this指向DOM,第二个this指向window
this关键是看执行环境, 第一次在DOM中,这个不需要太多解释; 第二次相当于window.callback(), 所以this指向window
你描述的第二种场景出现你理解的差异是因为name = "text";, 这一步赋值操作, 使得window.name = "text", 所以执行callback()会打出text

关于你验证想法的例子楼上都说出错误了。
补充:
1.如果事件函数中有一个内部函数func,在事件内部调用func时,func函数内部this实际指向window。
2.this的隐式绑定是作为对象的方法调用时才能生效。
3.对于1.我们可以使用call方法来修正

window.id = 'window';
  document.getElementById('div0').onclick = function(){
    alert(this.id);
    var callback = function(){
      alert(this.id)
    }
    callback.call(this);
  };

this 指向的是方法属性的所有者,第一个方法的所有者是DOM元素, 内部函数call由于没有申明所有者所以他的所有这是window

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题