V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
june4
V2EX  ›  前端开发

在 JavaScript 中,大块一次性数据放在函数中返回是不是比放在变量更省内存?

  •  
  •   june4 · 10 天前 · 889 次点击

    比如说在 javascript 中,我有一些原始数据,用于构造一个最终对象,所以这个 data 一次性用完就没用了。

    const data = { ... }
    const targetObj = build(data)
    

    那我是象上面那样放在一个模块变量里好呢,还是用个函数返回好?

    const data = () => ({ ... })
    const targetObj = build(data())
    

    如果这些数据比较大,用了函数,是不是省了数据一份在内存中复制品?

    8 条回复    2025-03-01 21:20:17 +08:00
    bojackhorseman
        1
    bojackhorseman  
       10 天前
    如果会对 data 进行变更那还是用函数返回对象的形式吧,不然追踪那里改了 data 将是一件头痛的事
    Linho1219
        2
    Linho1219  
       10 天前 via Android   ❤️ 1
    不用管,怎么舒服怎么写
    JS 有完善的垃圾回收机制,引擎会提前读代码做优化,知道你哪些用哪些不用。即使当前作用域还在,如果你后面 data 不用了就会自动回收掉
    (你想想你代码里多少个闭包,理论上这些闭包都会完整保留当前作用域,实际上不会,后面没用的就直接回收了)
    不要用这种“微优化”折腾自己,关注代码逻辑才是最重要的。写 JS 只要大体路线没错性能一般不是大问题
    ruxuan1306
        3
    ruxuan1306  
       10 天前
    没省,对象传参是传址,不是传值,后者反而构造 Object 时多了一层构造和调用函数的开销。
    june4
        4
    june4  
    OP
       10 天前
    @Linho1219 好吧,有空还是得亲自试验一下。你说的模块全局变量也会回收,我是不太相信。毕竟模块作用域可永不会消失,它引用的变量怎么就回收了。如果是小对象就算了,我这边这个数据对象有点大,如果微操一下能省点内存不是更好。


    @ruxuan1306 这和传址没关系吧?你也可以把 data 当 string 类型,用于生成一个页面,生成后原来的 string 就不要了。
    ruxuan1306
        5
    ruxuan1306  
       8 天前
    @june4 string 是值类型,object 是引用类型,看起来这是你的模糊点,找个 AI 聊聊
    june4
        6
    june4  
    OP
       8 天前
    @ruxuan1306 你都没搞清楚我说的是什么。你拿一个字符串模板生成另一个,是不是二个完全不同的字符串了?和值和引用有什么关系呢?
    ruxuan1306
        7
    ruxuan1306  
       4 天前
    @june4 我不知道你的水平,不知道如下表述你能否看懂:

    const data = { ... } // 在堆上申请了一个空间,储存对象 { ... },并把指针记为 data
    const targetObj = build(data) // 向 build 传入 data 这个指针,build 函数在堆上申请了一个新的空间,储存构造出的对象,并将其指针返回,被你记为 targetObj
    // build 执行完后,data 指向源对象,targetObj 指向构造出的对象,gc 回收不了任何对象

    const data = () => ({ ... }) // 在堆上申请了一个空间,储存函数 () => ({ ... }),并把指针记为 data
    const targetObj = build(data()) // 调用 data 函数,data 函数在堆上申请了一个新的空间,储存构造出的对象 { ... },并将其指针返回;向 build 函数传入 data 返回的对象指针,build 函数在堆上申请了一个新的空间,储存构造出的对象,并将其指针返回,被你记为 targetObj
    // build 执行完成后其栈空间会被释放,那个存在于其形参的指向堆源对象的指针也被释放,源对象将在稍后被 gc 回收; targetObj 指向构造出的对象


    这两种写法,前者在执行完成后内存占用高( gc 无法回收源对象),后者在执行过程中峰值内存占用高(多出一个函数对象的空间)


    另外你一直在用 string 类比,要说明的是,在 JavaScript 中基本类型包括 string 是按值传递的,传入函数时是拷贝,而不是像 object 一样是指针。
    june4
        8
    june4  
    OP
       4 天前
    @ruxuan1306 我不就说 data 这个全局变量不会回收嘛。
    另外 js 又不是 C++, string 传进去绝对不可能是复制一份内存,毕竟 js 没有修改字符串内容的能力为什么要传一份拷贝。

    至于哪种占用内存高还不一定,比如万一浏览器会在加载运行完 js 文件后释放了 js 源码所占内存,但函数可能有特殊,因为函数的 toString 会得到源码,所以函数可能会把对应源码复制函数对象,这样把 data 弄成函数省下的内存又在函数源码上完全找补回来了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5142 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 20ms · UTC 09:30 · PVG 17:30 · LAX 01:30 · JFK 04:30
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.