this 绑定(this Binding)

this 的绑定规则和上下文。


📚 this 绑定规则

1. 默认绑定(Default Binding)

非严格模式下,this 指向全局对象(浏览器中是 window):

function greet() {
  console.log(this); // window(浏览器中)
}
 
greet();

严格模式下,thisundefined

'use strict';
function greet() {
  console.log(this); // undefined
}
 
greet();

2. 隐式绑定(Implicit Binding)

方法调用时,this 指向调用该方法的对象:

const person = {
  name: 'Alice',
  greet() {
    console.log(`Hello, I'm ${this.name}`);
  }
};
 
person.greet(); // "Hello, I'm Alice"(this 指向 person)

隐式绑定丢失

const person = {
  name: 'Alice',
  greet() {
    console.log(`Hello, I'm ${this.name}`);
  }
};
 
const greet = person.greet;
greet(); // "Hello, I'm undefined"(this 丢失,指向全局对象)

3. 显式绑定(Explicit Binding)

使用 callapplybind 显式指定 this

call()

function greet(greeting) {
  console.log(`${greeting}, I'm ${this.name}`);
}
 
const person = { name: 'Alice' };
greet.call(person, 'Hello'); // "Hello, I'm Alice"

apply()

function greet(greeting, punctuation) {
  console.log(`${greeting}, I'm ${this.name}${punctuation}`);
}
 
const person = { name: 'Alice' };
greet.apply(person, ['Hello', '!']); // "Hello, I'm Alice!"

bind()

function greet() {
  console.log(`Hello, I'm ${this.name}`);
}
 
const person = { name: 'Alice' };
const boundGreet = greet.bind(person);
boundGreet(); // "Hello, I'm Alice"

4. new 绑定(new Binding)

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

function Person(name) {
  this.name = name;
}
 
const person = new Person('Alice');
console.log(person.name); // "Alice"

5. 箭头函数绑定(Arrow Function Binding)

箭头函数不绑定 this,继承外层作用域的 this

const person = {
  name: 'Alice',
  greet: function() {
    setTimeout(() => {
      console.log(`Hello, I'm ${this.name}`); // this 指向 person
    }, 100);
  }
};
 
person.greet(); // "Hello, I'm Alice"

对比普通函数:

const person = {
  name: 'Alice',
  greet: function() {
    setTimeout(function() {
      console.log(`Hello, I'm ${this.name}`); // this 指向 window
    }, 100);
  }
};
 
person.greet(); // "Hello, I'm undefined"

🎯 绑定优先级

优先级从高到低:

  1. new 绑定 > 显式绑定 > 隐式绑定 > 默认绑定
  2. 箭头函数(不参与优先级,继承外层)
// 示例:new 绑定优先级最高
function Person(name) {
  this.name = name;
}
 
const obj = {};
const person = Person.call(obj, 'Alice'); // 显式绑定
console.log(obj.name); // "Alice"
 
const person2 = new Person('Bob'); // new 绑定
console.log(person2.name); // "Bob"

💡 常见场景

1. 事件处理

class Button {
  constructor(text) {
    this.text = text;
    this.element = document.createElement('button');
    this.element.textContent = text;
    // 需要绑定 this
    this.element.addEventListener('click', this.handleClick.bind(this));
  }
  
  handleClick() {
    console.log(`Button "${this.text}" clicked`);
  }
}

2. 回调函数

class DataFetcher {
  constructor(url) {
    this.url = url;
  }
  
  fetch() {
    // 使用箭头函数保持 this
    fetch(this.url)
      .then(response => {
        this.handleResponse(response);
      });
  }
  
  handleResponse(response) {
    console.log(`Fetched from ${this.url}`);
  }
}

3. 方法作为回调

const person = {
  name: 'Alice',
  greet() {
    console.log(`Hello, I'm ${this.name}`);
  }
};
 
// ❌ this 丢失
setTimeout(person.greet, 100);
 
// ✅ 使用 bind
setTimeout(person.greet.bind(person), 100);
 
// ✅ 使用箭头函数
setTimeout(() => person.greet(), 100);

⚠️ 注意事项

1. 箭头函数不能改变 this

const person = {
  name: 'Alice',
  greet: () => {
    console.log(this.name); // this 指向外层(可能是 window)
  }
};
 
person.greet(); // undefined

2. 严格模式影响

'use strict';
function greet() {
  console.log(this); // undefined(非严格模式是 window)
}
 
greet();

3. 类方法自动绑定(实验性)

class Person {
  name = 'Alice';
  
  // 使用箭头函数自动绑定
  greet = () => {
    console.log(`Hello, I'm ${this.name}`);
  }
}

🔗 相关链接


参考


javascript this 绑定 context arrow-function