美文网首页
520继续卷,再来盘一盘js中this的指向问题

520继续卷,再来盘一盘js中this的指向问题

作者: 伊泽瑞尔灬 | 来源:发表于2023-05-18 22:33 被阅读0次

    JavaScript 中的 this 关键字是一个非常重要且常用的概念,它代表当前函数执行时的上下文对象。this 的指向在 JavaScript 中是非常灵活的,不同的情况下指向不同的对象,下面我们来详细讲解 this 的指向问题。

    常见this的绑定

    1. 默认绑定

    当函数没有明确指定 this 的绑定对象时,即在非严格模式下,this 的指向会默认绑定到全局对象上(在浏览器环境下是 window 对象,在 Node.js 环境下是 global 对象),例如:

    function foo() {
      console.log(this);
    }
    foo(); // 在浏览器环境下输出 window 对象,在 Node.js 环境下输出 global 对象
    
    2. 隐式绑定

    当函数作为对象的方法进行调用时,this 的指向会隐式绑定到调用该方法的对象上,例如:

    const obj = {
      name: 'John',
      sayName() {
        console.log(this.name);
      }
    };
    obj.sayName(); // 输出 John
    

    在上面的例子中,sayName 方法的调用者是 obj 对象,因此 this 的指向就会隐式地绑定到 obj 对象上,从而访问到 obj 对象的 name 属性。

    需要注意的是,如果在对象内部定义一个函数,并将其作为参数传递到其他函数中,那么该函数内部的 this 指向可能会发生改变,例如:

    const obj = {
      name: 'John',
      sayName() {
        console.log(this.name);
      },
      foo() {
        setTimeout(this.sayName, 1000);
      }
    };
    obj.foo(); // 在一些情况下会输出 undefined,而不是 John
    

    在上面的例子中,foo 方法内部通过 setTimeout 调用了 sayName 方法,由于 setTimeout 是一个独立的函数调用,因此其中的 this 指向会被绑定到全局对象上,导致 sayName 方法内部访问不到 obj 对象的 name 属性。

    3. 显示绑定

    通过使用 callapply 或者 bind 等函数,可以显式地绑定 this 的指向,例如:

    function foo() {
      console.log(this);
    }
    const obj = { name: 'John' };
    foo.call(obj); // 输出 { name: 'John' }
    foo.apply(obj); // 输出 { name: 'John' }
    const bar = foo.bind(obj);
    bar(); // 输出 { name: 'John' }
    

    在上面的例子中,通过 callapply 或者 bind 函数,将 foo 函数的 this 指向显式地绑定到 obj 对象上,从而访问到 obj 对象的属性。

    需要注意的是,当使用callapply 或者 bind 函数显式绑定 this 指向时,如果同时使用了默认绑定,那么默认绑定会被忽略。例如:

    function foo() {
      console.log(this);
    }
    const obj = { name: 'John' };
    foo.call(obj); // 输出 { name: 'John' }
    foo(); // 输出全局对象,因为此时使用了默认绑定
    

    在上面的例子中,虽然 foo.call(obj) 显式绑定了 this 指向,但在 foo() 调用时依然使用了默认绑定,因此 this 的指向是全局对象。

    4. new 绑定

    在使用 new 关键字调用构造函数时,this 的指向会被绑定到新创建的对象上,例如:

    function Person(name) {
      this.name = name;
    }
    const john = new Person('John');
    console.log(john.name); // 输出 John
    

    在上面的例子中,通过 new 关键字调用 Person 构造函数创建了一个新的对象 john,此时 this 的指向会被自动绑定到新创建的对象 john 上,从而将 name 属性添加到 john 对象中。

    需要注意的是,如果构造函数内部返回一个对象,那么 this 的指向会被忽略,返回的对象会被作为新创建的对象返回,例如:

    function Person(name) {
      this.name = name;
      return { age: 20 };
    }
    const john = new Person('John');
    console.log(john); // 输出 { age: 20 }
    

    在上面的例子中,虽然 Person 构造函数内部使用了 this,但返回了一个新的对象 { age: 20 },因此 this 的指向会被忽略,john 对象会被返回成为 new Person('John') 的结果。

    5.箭头展示中this的指向

    在箭头函数中,this 的指向是固定的,始终指向外层函数的 this。箭头函数的 this 指向是静态的,一旦确定了指向,就无法更改。例如:

    function foo() {
      return () => {
        console.log(this);
      }
    }
    const obj = { name: 'John' };
    const bar = foo.call(obj); // bar 是一个箭头函数
    bar(); // 输出 { name: 'John' }
    

    在上面的例子中,foo() 函数返回了一个箭头函数,该箭头函数的 this 指向 foo() 函数的 this,即 obj 对象。当调用 bar() 函数时,箭头函数的 this 指向仍然是 obj 对象,因此输出了 { name: 'John' }

    需要注意的是,如果箭头函数是在全局作用域中定义的,那么它的 this 指向就是全局对象。例如:

    const arrow = () => {
      console.log(this);
    };
    arrow(); // 输出全局对象
    

    在上面的例子中,arrow() 是在全局作用域中定义的箭头函数,因此它的 this 指向是全局对象。

    需要注意的问题

    除了上面提到的情况外,还有一些值得注意的地方:

    1. 严格模式下的默认绑定

    在严格模式下,默认绑定的行为会与非严格模式有所不同。在非严格模式下,如果函数调用不符合任何绑定规则,则默认绑定会绑定到全局对象上。而在严格模式下,如果函数调用不符合任何绑定规则,则默认绑定的 this 值会被设置为 undefined,例如:

    function foo() {
      'use strict';
      console.log(this);
    }
    foo(); // 输出 undefined
    

    在上面的例子中,虽然 foo() 函数没有任何显式绑定,但在严格模式下,this 的值会被设置为 undefined

    1. DOM 事件处理函数中的 this

    在处理 DOM 事件时,事件处理函数中的 this 指向的是触发事件的元素。例如:

    <button id="my-button">Click me</button>
    
    const button = document.getElementById('my-button');
    button.addEventListener('click', function() {
      console.log(this); // 输出按钮元素
    });
    

    在上面的例子中,事件处理函数中的 this 指向的是按钮元素,因为该函数是通过按钮元素的 addEventListener 方法注册的。

    1. jQuery 中的 this

    在 jQuery 中,大多数方法都会返回 jQuery 对象,以便支持链式调用。在 jQuery 方法链中,this 指向的始终是 jQuery 对象本身,例如:

    $('.my-class')
      .css('color', 'red') // 返回 jQuery 对象,this 指向的是该对象
      .addClass('my-class') // 返回 jQuery 对象,this 指向的是该对象
      .on('click', function() {
        console.log(this); // 输出点击的元素
      });
    

    在上面的例子中,$('.my-class') 方法返回的是 jQuery 对象,后续的方法链中的 this 始终指向该对象。在事件处理函数中,this 指向的是触发事件的元素。

    总结

    1. 默认绑定:在函数调用中,如果没有其他绑定规则适用,则默认绑定到全局对象或 undefined(严格模式下)。
    2. 隐式绑定:在函数调用中,如果函数作为对象的方法被调用,则隐式绑定到该对象。
    3. 显式绑定:可以使用 callapplybind 方法显式指定函数的 this
    4. new 绑定:在使用 new 运算符创建新对象时,会自动将 this 绑定到新对象上。
    5. 箭头函数绑定:箭头函数的 this 始终指向外层函数的 this,无法通过 callapplybind 方法更改。
    6. 严格模式下的默认绑定:在严格模式下,默认绑定的 this 值会被设置为 undefined
    7. DOM 事件处理函数中的 this:在处理 DOM 事件时,事件处理函数中的 this 指向的是触发事件的元素。
    8. jQuery 中的 this:在 jQuery 方法链中,this 始终指向 jQuery 对象本身,在事件处理函数中指向触发事件的元素。
    9. 谁在调用函数,this 指向就是谁,不然就是全局对象。
      然而,也存在一些特殊情况,其中 this 的指向不仅仅取决于调用函数的对象。例如,使用 callapply 或者 bind 等方法可以显式地指定函数的 this。此外,箭头函数具有固定的词法作用域,其中的 this 始终指向外层函数的 this,而不会被调用方式所改变。

    因此,虽然 "谁在调用函数,this 指向就是谁" 可以在一些情况下成立,但为了准确理解 this 的指向,需要考虑更多的因素,如绑定规则、箭头函数和特殊的调用方式。

    了解这些绑定规则对于正确理解 JavaScript 中 this 的指向非常重要。

    365学习不打烊,可以关注我的公众号:程序员每日三问。每天向你推送面试题,算法及干货,期待你的点赞和关注。

    相关文章

      网友评论

          本文标题:520继续卷,再来盘一盘js中this的指向问题

          本文链接:https://www.haomeiwen.com/subject/ocsgsdtx.html