You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript中闭包与原型的区别及闭包使用原因探讨

闭包 vs 原型:区别、关联与闭包的价值

Great question! 你写的两个标签生成函数确实能实现类似效果,但背后的逻辑完全不同——一个靠闭包锁住状态,另一个靠原型链共享方法。咱们结合你的代码一步步拆解:

先把你的代码格式化方便参考:

// Closure function
function createLI(tags) {
  return function(...args) {
    if (args.length > 1) {
      return args.map((item) => {
        return "<" + tags + ">" + item + "</" + tags + ">"
      })
    } else {
      return "<" + tags + ">" + args + "</" + tags + ">"
    }
  }
}
var tag = createLI('li');
console.log(tag('test'));

// Prototype function
let Newfunction = function(x) {
  this.content = x;
}
Newfunction.prototype.aswrapper = function(...args) {
  if (args.length > 1) {
    return args.map((item) => {
      return "<" + this.content + ">" + item + "</" + this.content + ">"
    })
  } else {
    return "<" + this.content + ">" + args + "</" + this.content + ">"
  }
}
let heading = new Newfunction('h1');
console.log(heading.aswrapper('sometextprint'));

一、核心区别

1. 状态存储的本质

  • 闭包:createLI返回的内部函数,通过闭包“记住”了外部作用域的tags参数。这个状态是绑定在返回的函数实例上的——每个通过createLI创建的函数(比如tag)都有自己独立的tags值,互不干扰。
    比如你再创建一个生成<p>标签的函数:
    const tagP = createLI('p');
    console.log(tagP('test')); // <p>test</p>
    // tag和tagP的tags完全独立
    
  • 原型:Newfunction把状态(content)存在实例的this上,而aswrapper方法是挂在Newfunction.prototype上的——所有Newfunction的实例都会共享同一个原型方法,状态则是每个实例自己的。
    比如:
    const headingH2 = new Newfunction('h2');
    console.log(headingH2.aswrapper('text')); // <h2>text</h2>
    // heading和headingH2的aswrapper是同一个函数
    console.log(heading.aswrapper === headingH2.aswrapper); // true
    

2. 内存与复用效率

  • 闭包:每个闭包函数都会携带自己的外部作用域,创建大量闭包时会占用更多内存(因为每个都有独立的作用域链)。但好处是不用实例化对象,直接调用函数就行,写法更轻量化。
  • 原型:原型上的方法是所有实例共享的,内存占用更高效——不管创建多少实例,方法只存在一份。但必须通过new创建实例,更偏向面向对象的写法。

3. 语法风格与适用场景

  • 闭包:属于函数式编程风格,适合创建“预配置”的函数(比如你的标签生成器),或者封装私有变量(外部无法直接修改tags,只能通过返回的函数操作)。
  • 原型:是JS面向对象编程的核心,适合创建多个具有相同行为但不同状态的对象,比如类的继承就是基于原型链实现的。

二、两者的关联

虽然看起来是不同机制,但在JS里它们是相辅相成的:

  1. 原型方法可以结合闭包:比如你可以在原型方法里创建闭包,用来保存一些不想暴露给外部的私有状态。
  2. 闭包可以模拟原型特性:比如用闭包创建多个共享逻辑的函数,但这样不如原型高效,因为每个函数都有独立的逻辑副本。
  3. 都依赖JS的作用域规则:闭包靠词法作用域查找变量,原型靠原型链查找方法——本质上都是JS查找标识符的规则延伸。

三、为什么要使用闭包?

闭包是JS里非常强大的特性,主要有这些核心用途:

  1. 封装私有变量:比如createLI里的tags,外部代码无法直接修改它,只能通过返回的函数来使用,避免了全局污染和意外修改。
  2. 创建函数工厂:就像你写的标签生成器,通过闭包可以快速批量创建预配置好的函数(生成li、p、h1等标签),代码更简洁。
  3. 保存执行上下文状态:比如在定时器、事件监听里,闭包可以记住回调函数创建时的环境变量,避免变量被覆盖的经典问题。
  4. 实现模块化:在ES6模块出现之前,很多前端模块都是用闭包封装私有逻辑,只暴露需要的接口。

举个封装私有变量的经典例子:

function createCounter() {
  let count = 0; // 外部无法直接访问的私有变量
  return {
    increment: () => count++,
    getCount: () => count
  }
}
const counter = createCounter();
counter.increment();
console.log(counter.getCount()); // 1
// 你没法直接修改count,只能通过提供的方法操作

内容的提问来源于stack exchange,提问作者pixellab

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 03:54:19