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

JavaScript中嵌套在其他对象的方法如何存储?覆写原方法后仍可执行原因

问题解答

为什么修改fn.getN1后obj[1]()仍然能执行旧方法?

这是JS中引用类型的赋值规则决定的:

  • 函数属于引用类型,你执行let obj = {1: fn.getN1}时,是把fn.getN1指向的函数对象的内存地址复制给了obj[1],此时obj[1]和fn.getN1是两个独立的属性,只是指向同一个函数对象而已。
  • 后续执行fn.getN1 = "test",只是把fn对象的getN1属性的指向,从原来的函数地址修改为了字符串test的地址,这个操作不会影响obj[1]的指向。
  • 原有的getN1函数对象因为仍然被obj[1]引用,不会被垃圾回收机制清理,所以调用obj[1]()依然可以正常执行。你打印fn看不到旧方法,只是因为fn的getN1属性已经不再指向这个函数对象,不等于函数对象本身从内存中被清除了。

你提供的代码执行逻辑也符合这个规则:

function Factory() {
    let n = 0;

    function getN1() {
        console.log(n);
    }
    
    function getN2() {
        console.log(n);
    }

    function incrN() {
        n++
    }

    return {getN1, getN2, incrN}
    
}

let fn = Factory();

let obj = {1: fn.getN1, 2: fn.incrN}

fn.getN1 = "test";
console.log(fn);

obj["2"](); // 闭包变量n变为1

obj[1](); // 输出1
fn.getN2(); // 输出1
console.log(fn.getN1); // 输出test

这种写法是否属于不良实践?

不存在绝对的好坏,分场景判断:

  • 如果你是故意要缓存原始的方法引用、避免原对象属性修改带来的影响,这种写法是完全合理的。
  • 如果你是误以为修改原对象的属性会同步更新所有之前的赋值引用,那这个特性就是容易出bug的坑点。实际开发中如果要做关联更新,不要直接赋值函数引用,可以改成让obj存储方法的键名:let obj = {1: 'getN1', 2: 'incrN'},调用时写fn[obj[1]](),就能同步fn的属性修改。
  • 额外注意:如果方法内部用到了this,直接把方法赋值给其他对象调用时,this的指向会变成调用它的新对象,会出现预期外的问题。这种场景下如果要保留原this指向,需要用bind方法绑定:let obj = {1: fn.getN1.bind(fn)}。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 08:36:07