乐趣区

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

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 多平台公布

退出移动版