this 与 bind:JavaScript 中的“归属感”难题

0 阅读3分钟

引言:

在 JavaScript 的世界里,this 是一个有点“随遇而安”的存在。它不像其他语言中的 this 那样坚定地指向类实例,而是根据函数的调用方式动态变化。这种灵活性带来了强大,也带来了困惑。于是,bind 出现了,它像一位“职场导师”,帮助 this 找到归属感。


一、this:谁调用我,我就指向谁

JavaScript 中的 this 是一个在函数执行时动态绑定的关键字。它的值并不取决于函数定义的位置,而是取决于函数如何被调用

我们来看几种常见的绑定方式:

1. 默认绑定(非严格模式)

function foo() {
  console.log(this);
}
foo(); // 输出 window(浏览器环境)

在非严格模式下,this 默认绑定到全局对象(浏览器中是 window)。

2. 隐式绑定(通过对象调用)

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

函数被对象调用时,this 指向该对象。

3. 显式绑定(call / apply / bind)

const person = { name: 'Bob' };
function sayHi() {
  console.log('Hi, ' + this.name);
}
sayHi.call(person); // Hi, Bob

通过 callapplybind,可以显式地指定 this 的指向。

4. 构造函数绑定

function Person(name) {
  this.name = name;
}
const p = new Person('Charlie');
console.log(p.name); // Charlie

使用 new 调用构造函数时,this 指向新创建的对象。


二、箭头函数中的 this:继承自外层

箭头函数没有自己的 this,它继承的是外层作用域的 this

const obj = {
  name: 'David',
  sayName: () => {
    console.log(this.name);
  }
};
obj.sayName(); // 输出 undefined(严格模式下)

在这个例子中,this 指向的是全局对象或 undefined,而不是 obj。因此,箭头函数在某些场景下会带来意想不到的结果。


三、bind:为 this 指定一个“终身归属”

bind 是 Function.prototype 上的一个方法,它的作用是创建一个新函数,并将该函数的 this 绑定到指定的对象上。

function sayName() {
  console.log(this.name);
}

const user = { name: 'Eve' };

const boundSayName = sayName.bind(user);
boundSayName(); // 输出 Eve

即使你把 boundSayName 作为回调函数传给其他地方,它也会坚定地指向 user


bind 的三大用途:

1. 固定 this 的指向

这是 bind 最常见的用途。它能确保函数在任何调用方式下,this 都指向你指定的对象。

const obj = {
  value: 42,
  print: function () {
    setTimeout(function () {
      console.log(this.value); // 如果不 bind,this 指向 window
    }.bind(this), 100);
  }
};

2. 预设参数(偏函数)

除了绑定 thisbind 还可以绑定函数的前几个参数,形成“偏函数”。

function multiply(a, b) {
  return a * b;
}

const double = multiply.bind(null, 2);
console.log(double(5)); // 输出 10

3. 事件处理中防止 this 丢失

这是 bind 最常见的实际应用场景之一:

const button = document.querySelector('#myButton');
const obj = {
  name: 'Frank',
  handleClick: function () {
    console.log(`${this.name} 点击了按钮`);
  }
};

button.addEventListener('click', obj.handleClick.bind(obj));

这样可以确保 this 始终指向 obj,而不是指向 button


四、bind 的局限性:不能被“二次绑定”

一旦函数被 bind 绑定,它的 this 就不会再改变了。即使你用 callapply 试图修改它,也不会生效。

function foo() {
  console.log(this.name);
}

const obj1 = { name: 'Grace' };
const obj2 = { name: 'Helen' };

const bound = foo.bind(obj1);
bound.call(obj2); // 输出 Grace

所以,bind 是个“忠诚的战士”,一旦绑定,绝不背叛。


五、总结:this 与 bind 的关系

this 是动态绑定的上下文,调用方式决定其指向,可被修改;而 bind 会返回一个新函数,固定绑定 this 和参数,不可更改。二者配合使用,可精准控制函数执行环境。

简单来说,this 是一个灵活但容易迷失的角色,而 bind 则是它的“指南针”,帮助它找到稳定的归属。


结语:

在 JavaScript 的世界里,this 有时会“走失”,但它并不孤单,bind 总是能把它带回正确的轨道。理解 this 的绑定规则,掌握 bind 的使用,是每个 JavaScript 开发者必经的成长之路。