Skip to content

JavaScript 的 this 机制深度解析

全局环境中的 this

  • 在浏览器全局环境下,this 始终指向 window 对象(等同于 self
  • var 声明的全局变量会挂载到 window 属性上
  • letconst 声明的变量不会挂载到 window
javascript
var a = 10;
let b = 20;
console.log(this === window); // true
console.log(window === self); // true
console.log(window.a); // 10
console.log(window.b); // undefined

函数调用中的 this

严格模式 vs 非严格模式

模式this 指向示例
严格模式undefinedfunction f() { "use strict"; console.log(this) }undefined
非严格模式window 对象function f() { console.log(this) }window

对象方法中的 this

  • 对象方法中的 this(除箭头函数外)指向调用该方法的对象
  • 当方法被提取为独立函数调用时,this 可能丢失
javascript
const obj = {
  name: "hulei",
  getName() {
    return this.name;
  },
};

console.log(obj.getName()); // "hulei" (this指向obj)

const getNameFunc = obj.getName;
console.log(getNameFunc()); // undefined (this指向window)

构造函数中的 this

  • 构造函数中的 this 默认指向新创建的实例对象
  • 如果构造函数返回对象,则 this 指向该返回对象
  • 如果返回非对象值,则 this 仍指向实例对象
javascript
function User(name) {
  this.name = name;
}

const user1 = new User("Alice");
console.log(user1.name); // "Alice" (this指向实例)

function Admin(name) {
  this.name = name;
  return { name: "Admin User" }; // 返回对象
}

const admin = new Admin("Bob");
console.log(admin.name); // "Admin User" (this指向返回对象)

call & apply 改变 this 指向

  • 使用 callapply 可以显式改变函数的 this 指向
  • 箭头函数的 this 无法通过 callapply 改变
javascript
function greet() {
  console.log(`Hello, ${this.name}`);
}

const person = { name: "John" };
greet.call(person); // "Hello, John"

箭头函数的 this

核心特性

  • 箭头函数的 this 在定义时确定,而非调用时
  • 指向定义时上层作用域的 this
  • 无法通过 callapplybind 改变 this 指向

不同场景表现

场景this 指向原因说明
对象方法外层作用域的 this通常是 window
普通函数内部外层函数的 this取决于外层函数调用方式
构造函数内部新创建的实例对象箭头函数定义在构造函数作用域内
全局作用域window 对象最外层作用域
javascript
const obj = {
  value: "object value",
  regularMethod: function () {
    console.log("Regular method:", this.value);
  },
  arrowMethod: () => {
    console.log("Arrow method:", this.value);
  },
  nested: function () {
    const innerArrow = () => {
      console.log("Nested arrow:", this.value);
    };
    innerArrow();
  },
};

obj.regularMethod(); // "Regular method: object value"
obj.arrowMethod(); // "Arrow method: undefined" (指向window)
obj.nested(); // "Nested arrow: object value" (指向obj)

this 绑定规则总结

规则类型this 指向优先级是否可改变
new 绑定新创建的实例对象最高
显式绑定call/apply/bind 指定
隐式绑定调用上下文对象
默认绑定全局对象或 undefined最低
箭头函数定义时的外层 this固定

经典案例分析

案例 1:对象方法与嵌套函数

javascript
const point = {
  x: 20,
  moveTo: function(x) {
    // 普通函数,this 取决于调用方式
    const moveX = function(x) {
      this.x = x; // this 指向 window
    };
    moveX(x);
  },
  getX: function() {
    return this.x; // this 指向调用对象
  }
};

point.moveTo(1);
console.log(point.getX()); // 20 (未改变)

// 解决方案:使用箭头函数或绑定 this
moveTo: function(x) {
  const moveX = (x) => {
    this.x = x; // this 指向 point
  };
  moveX(x);
}

案例 2:箭头函数与对象方法

javascript
const obj = {
  value: 42,
  getValue: function () {
    // 箭头函数捕获外层 this
    const arrowFn = () => {
      console.log(this.value); // 42 (指向 obj)
    };
    arrowFn();

    // 尝试改变 this 指向失败
    arrowFn.call({ value: 100 }); // 仍输出 42
  },
  getValueArrow: () => {
    // 箭头函数直接定义在对象中
    console.log(this.value); // undefined (指向 window)
  },
};

obj.getValue(); // 42
obj.getValueArrow(); // undefined

案例 3:类与箭头函数

javascript
class Counter {
  count = 0;

  // 原型方法:this 动态绑定
  increment() {
    this.count++;
    console.log(this.count);
  }

  // 实例方法(箭头函数):this 静态绑定
  decrement = () => {
    this.count--;
    console.log(this.count);
  };
}

const counter = new Counter();
const increment = counter.increment;
const decrement = counter.decrement;

increment(); // TypeError: Cannot read property 'count' of undefined
decrement(); // -1 (箭头函数绑定实例)

箭头函数特殊性质

  1. 没有自己的 this:继承自定义时的外层作用域
  2. 没有 prototype 属性:不能作为构造函数使用
  3. 没有 arguments 对象:需使用剩余参数 (...args) 替代
  4. 不能使用 new 调用:没有构造能力
javascript
const arrow = () => {};
console.log(arrow.prototype); // undefined
try {
  new arrow(); // TypeError: arrow is not a constructor
} catch (e) {
  console.error(e.message);
}

最佳实践建议

  1. 对象方法:使用普通函数确保 this 正确指向调用对象
  2. 回调函数:使用箭头函数避免 this 丢失问题
  3. 类组件:使用箭头函数绑定实例方法
  4. 工具函数:优先使用箭头函数避免意外的 this 绑定
  5. 构造函数:避免使用箭头函数定义方法