【JavaScript】day22-closure-this

作者:mario 发布时间: 2026-08-26 阅读量:10 评论数:0

第二十二天:闭包与 this — JS 面试必考的两个概念

蜗牛往上爬 · 前端工业可视化学习笔记 第 22 篇
函数基础学完了,今天挑战两个"难点":闭包和 this。闭包让函数拥有"私有记忆",this 则是 JS 最容易搞混的机制。不用死记定义——用工业场景(计数器、状态缓存)来理解,一目了然。


目录


一、什么是闭包

闭包 = 函数 + 它能访问的外部变量。最直观的形式:函数返回另一个函数。

// 经典闭包:计数器
function createCounter() {
  var count = 0;  // 被"关"在闭包里,外部无法直接访问

  return function () {
    count++;       // 内部函数可以访问并修改 count
    return count;
  };
}

var counter = createCounter();
console.log(counter());  // 1
console.log(counter());  // 2
console.log(counter());  // 3
// count 一直"活着",每次调用都在上一次基础上加 1

// 两个计数器互不干扰
var counter2 = createCounter();
console.log(counter2());  // 1(独立空间)

为什么需要闭包?

// ❌ 不用闭包:count 暴露在全局,任何代码都能改
var count = 0;
function add() { count++; }

// ✅ 用闭包:count 被保护,只能通过 counter() 修改
var counter = createCounter();

二、闭包的工业场景:状态缓存

/**
 * 设备状态查询缓存
 * 缓存数据被闭包保护,只能通过方法访问
 */
function createStatusCache() {
  var cache = {};  // 私有缓存

  return {
    get: function (deviceId) {
      return cache[deviceId] || null;
    },
    set: function (deviceId, status) {
      cache[deviceId] = status;
    },
    clear: function () {
      cache = {};
    }
  };
}

var statusCache = createStatusCache();
statusCache.set("CNC-001", "运行中");
console.log(statusCache.get("CNC-001"));  // "运行中"

另一个常见场景——带前缀的日志器:

function createLogger(prefix) {
  return function (message) {
    console.log("[" + prefix + "] " + message);
  };
}

var warnLogger = createLogger("告警");
var infoLogger = createLogger("信息");

warnLogger("温度过高");  // [告警] 温度过高
infoLogger("系统启动");  // [信息] 系统启动

三、this 指向:谁调用指向谁

// 场景 1:普通函数调用 → this 指向 window(浏览器)/ global(Node)
function showThis() {
  console.log(this);
}
showThis();

// 场景 2:对象方法调用 → this 指向调用它的对象
var device = {
  name: "CNC-001",
  temp: 65,
  showInfo: function () {
    console.log("设备:" + this.name + ",温度:" + this.temp);
  }
};

device.showInfo();  // "设备:CNC-001,温度:65"
// this === device,因为 device 调用了 showInfo

一句话记住 this:看"点号前面是谁",this 就是谁。


四、this 的坑:赋值后丢失

var device = {
  name: "CNC-001",
  showInfo: function () {
    console.log(this.name);  // this 取决于"谁调用"
  }
};

device.showInfo();  // "CNC-001" ✅(device 调用)

// ❌ 坑 1:赋值给变量 → 变成普通函数调用
var fn = device.showInfo;
fn();  // undefined(this 指向 window,window.name 不存在)

// ❌ 坑 2:作为回调传递
setTimeout(device.showInfo, 1000);
// undefined!内部相当于:var fn = device.showInfo; fn();

这个坑在事件回调和定时器中非常常见。ES6 箭头函数解决了这个问题——箭头函数没有自己的 this,继承外层的 this。第 12 周详细讲。


五、IIFE 立即执行函数

// IIFE:Immediately Invoked Function Expression(立即执行函数)
// 声明的同时立即执行,创建独立作用域

(function () {
  var privateVar = "只在这个作用域内有效";
  console.log("IIFE 执行了");
})();
// console.log(privateVar);  // ❌ 外部无法访问

// 常见用法:只暴露需要的内容
var counterModule = (function () {
  var count = 0;  // 私有

  return {
    increment: function () { count++; },
    getValue: function () { return count; }
  };
})();

counterModule.increment();
counterModule.increment();
console.log(counterModule.getValue());  // 2
// count 无法被外部直接修改 ✅

IIFE 是 ES6 模块化出现之前的主流"模块"写法,很多老代码库(jQuery 插件等)都在用。


六、总结

概念

关键点

闭包

函数 + 外部变量;函数返回函数时形成

闭包作用

保护私有数据、状态缓存、延迟执行

this 规则

谁调用指向谁(看点号前面)

this 的坑

方法赋值给变量/回调后,this 丢失指向 window

IIFE

(function(){})(),创建独立作用域

🎯 闭包和 this 是 JS 进阶的分水岭。第 12 周的箭头函数会再次提到 this——到那时你会彻底明白为什么箭头函数能解决 this 丢失问题。

评论