如何利用闭包在非严格模式下有效捕获并利用 this 关键字避免全局污染?

2026-05-08 00:561阅读0评论SEO资源
  • 内容介绍
  • 相关推荐

本文共计778个文字,预计阅读时间需要4分钟。

如何利用闭包在非严格模式下有效捕获并利用 this 关键字避免全局污染?

在非严格模式下,在嵌套函数中直接使用 `this` 会导致其失去对上层对象上下文的引用,自动绑定到全局对象(如 `window`)。这会导致意外的属性读写。封装本身不捕获 `this`,但可以通过变量保存 `this` 的值,然后在内部函数中通过作用域链访问。这是最常用、最可靠的做法。

用变量缓存外层 this(that / self)

在外部函数开头,将当前 this 赋值给一个局部变量(如 const that = this),内部函数即可安全引用该变量:

  • 适用于所有环境(包括老旧浏览器和非严格模式)
  • 逻辑清晰,调试友好,不会受调用方式影响
  • 注意变量命名要避免覆盖(如不用 thisself 在全局作用域已定义的情况)

示例:

const obj = {
  name: 'Alice',
  init() {
    const that = this; // 缓存当前 this
    setTimeout(function() {
      console.log(that.name); // 正确输出 'Alice'
    }, 100);
  }
};

改用箭头函数(ES6+ 环境推荐)

箭头函数不绑定自己的 this,而是继承定义时所在词法作用域的 this 值,天然规避了嵌套函数的 this 丢失问题:

  • 简洁、语义明确,无需额外变量
  • 仅在支持 ES6 的环境中可用(现代浏览器、Node.js 4+)
  • 不能用于需要动态 this 的场景(如事件监听器需指向触发元素)

示例:

obj.init = function() {
  setTimeout(() => {
    console.log(this.name); // this 指向 obj,无需缓存
  }, 100);
};

用 bind 显式绑定 this

对普通函数调用前使用 .bind(this),强制其 this 指向外层上下文:

  • 适合一次性回调,尤其是传给第三方 API 时
  • 每次调用都会创建新函数,可能有轻微性能开销
  • call/apply 更适合延迟执行场景(如定时器、事件)

示例:

obj.init = function() {
  setTimeout(function() {
    console.log(this.name);
  }.bind(this), 100);
};

避免在闭包中直接依赖 this 的隐式行为

闭包只捕获变量,不捕获执行上下文;若内部函数本身又作为方法被调用(如被赋给另一个对象属性后调用),this 仍会重新绑定。因此:

  • 不要假设“闭包里的函数一定保持外层 this”
  • 若需长期持有对象上下文,优先用缓存变量或箭头函数
  • 对异步回调、事件处理器等不确定调用方式的函数,必须显式处理 this

本文共计778个文字,预计阅读时间需要4分钟。

如何利用闭包在非严格模式下有效捕获并利用 this 关键字避免全局污染?

在非严格模式下,在嵌套函数中直接使用 `this` 会导致其失去对上层对象上下文的引用,自动绑定到全局对象(如 `window`)。这会导致意外的属性读写。封装本身不捕获 `this`,但可以通过变量保存 `this` 的值,然后在内部函数中通过作用域链访问。这是最常用、最可靠的做法。

用变量缓存外层 this(that / self)

在外部函数开头,将当前 this 赋值给一个局部变量(如 const that = this),内部函数即可安全引用该变量:

  • 适用于所有环境(包括老旧浏览器和非严格模式)
  • 逻辑清晰,调试友好,不会受调用方式影响
  • 注意变量命名要避免覆盖(如不用 thisself 在全局作用域已定义的情况)

示例:

const obj = {
  name: 'Alice',
  init() {
    const that = this; // 缓存当前 this
    setTimeout(function() {
      console.log(that.name); // 正确输出 'Alice'
    }, 100);
  }
};

改用箭头函数(ES6+ 环境推荐)

箭头函数不绑定自己的 this,而是继承定义时所在词法作用域的 this 值,天然规避了嵌套函数的 this 丢失问题:

  • 简洁、语义明确,无需额外变量
  • 仅在支持 ES6 的环境中可用(现代浏览器、Node.js 4+)
  • 不能用于需要动态 this 的场景(如事件监听器需指向触发元素)

示例:

obj.init = function() {
  setTimeout(() => {
    console.log(this.name); // this 指向 obj,无需缓存
  }, 100);
};

用 bind 显式绑定 this

对普通函数调用前使用 .bind(this),强制其 this 指向外层上下文:

  • 适合一次性回调,尤其是传给第三方 API 时
  • 每次调用都会创建新函数,可能有轻微性能开销
  • call/apply 更适合延迟执行场景(如定时器、事件)

示例:

obj.init = function() {
  setTimeout(function() {
    console.log(this.name);
  }.bind(this), 100);
};

避免在闭包中直接依赖 this 的隐式行为

闭包只捕获变量,不捕获执行上下文;若内部函数本身又作为方法被调用(如被赋给另一个对象属性后调用),this 仍会重新绑定。因此:

  • 不要假设“闭包里的函数一定保持外层 this”
  • 若需长期持有对象上下文,优先用缓存变量或箭头函数
  • 对异步回调、事件处理器等不确定调用方式的函数,必须显式处理 this