关于程序员:520继续卷再来盘一盘js中this的指向问题

32次阅读

共计 3872 个字符,预计需要花费 10 分钟才能阅读完成。

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 学习不打烊,能够关注我的公众号: 程序员每日三问 。每天向你推送面试题,算法及干货,期待你的点赞和关注。

本文由 mdnice 多平台公布

正文完
 0