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

如何优雅地重构两个高度相似的JavaScript函数

重构高度相似的JavaScript函数:优雅合并重复代码

提问场景

我有两个高度相似的JavaScript函数,希望将代码优雅地重构为单一函数,仅少数几行代码存在差异——其中一个函数比另一个多3行代码。

原始代码:

function doStuffForFacebook() { 
  var example = "toto" 
  //about 7 lines of code 
  resizeScale = 1 
}
function doStuffforYoutube() { 
  var example = "toto" 
  //the VERY SAME 7 lines of code as those inside doStuffForFacebook() 
  //the 3 lines which are different from above 
  if ( typeof cryptoVideoX !== "undefined" && cryptoVideoX !== null && cryptoVideoX !== 0 ) { 
    var vidRatio = cryptoVideoX / netVideoY; 
  } else { 
    //no crypto video add-on by source 
    var vidRatio = netVideoRatio; 
  } 
  var manually_recalculated_width_to_have_full_screen_height_video = Math.round(vidRatio * winHeight);// fb only accepts rounded values 
  $fbPlayer.attr('data-width', manually_recalculated_width_to_have_full_screen_height_video ); 
  resizeScale = 1 
}

重复这7多行代码只为了几行差异,我认为可以优化。我考虑过使用回调的方式实现,如下所示:

function doStuffForFacebook() { 
  resizeVideo(null);//nil because here no callback is necessary 
}
function doStuffforYoutube() { 
  resizeVideo(addSomeCodeCallback); 
}
function resizeVideo(callback) { 
  var example = "toto" 
  //the 7 lines of common CODE 
  callback(); 
  resizeScale = 1 
}
function addSomeCodeCallback() { 
  if ( typeof cryptoVideoX !== "undefined" && cryptoVideoX !== null && cryptoVideoX !== 0 ) { 
    var vidRatio = cryptoVideoX / netVideoY; 
  } else { 
    //no crypto video add-on by source 
    var vidRatio = netVideoRatio; 
  } 
  var manually_recalculated_width_to_have_full_screen_height_video = Math.round(vidRatio * winHeight);// fb only accepts rounded values 
  $fbPlayer.attr('data-width', manually_recalculated_width_to_have_full_screen_height_video ); 
}

我知道可以拆分前后逻辑为单独函数,但不想这么做,因为这些逻辑属于大型if/else块,整体更合理。请问如何按照JavaScript最佳实践正确实现?


几种符合最佳实践的重构方案

方案一:可选参数+条件分支(最直观易维护)

这种方式适合差异代码少、平台数量不多的场景,核心逻辑集中,可读性拉满:

// 核心通用函数,接收平台标识参数
function doStuff(platform) {
  var example = "toto";
  // 7行通用代码
  
  // 仅针对Youtube执行差异化逻辑
  if (platform === 'youtube') {
    // 用三元表达式简化原有的if/else,更简洁
    const vidRatio = typeof cryptoVideoX !== "undefined" && cryptoVideoX !== null && cryptoVideoX !== 0 
      ? cryptoVideoX / netVideoY 
      : netVideoRatio;
    // 优化变量名,提升语义化
    const fullScreenWidth = Math.round(vidRatio * winHeight);
    $fbPlayer.attr('data-width', fullScreenWidth);
  }
  
  resizeScale = 1;
}

// 保留原有的入口函数,兼容旧调用逻辑
function doStuffForFacebook() {
  doStuff('facebook');
}

function doStuffForYoutube() {
  doStuff('youtube');
}

方案二:优化回调方案(函数式风格,灵活度高)

如果你偏爱回调的思路,可以优化掉null传参的尴尬,直接用匿名回调内联差异逻辑,代码更紧凑:

function doStuff(customLogic) {
  var example = "toto";
  // 7行通用代码
  
  // 仅当传入有效回调时才执行,避免报错
  typeof customLogic === 'function' && customLogic();
  
  resizeScale = 1;
}

function doStuffForFacebook() {
  doStuff(); // 无需传null,简洁清晰
}

function doStuffForYoutube() {
  // 直接把差异逻辑写成匿名回调传入,不用单独定义函数
  doStuff(() => {
    const vidRatio = typeof cryptoVideoX !== "undefined" && cryptoVideoX !== null && cryptoVideoX !== 0 
      ? cryptoVideoX / netVideoY 
      : netVideoRatio;
    const fullScreenWidth = Math.round(vidRatio * winHeight);
    $fbPlayer.attr('data-width', fullScreenWidth);
  });
}

方案三:配置对象模式(扩展性最强)

如果未来可能新增更多平台,或者差异逻辑会变得复杂,用配置对象的方式更符合开闭原则——新增平台无需修改核心函数,只需要添加配置项:

// 定义各平台的差异化逻辑配置
const platformConfigs = {
  facebook: {
    // Facebook不需要额外逻辑,留空函数
    afterCommonLogic: () => {}
  },
  youtube: {
    afterCommonLogic: () => {
      const vidRatio = typeof cryptoVideoX !== "undefined" && cryptoVideoX !== null && cryptoVideoX !== 0 
        ? cryptoVideoX / netVideoY 
        : netVideoRatio;
      const fullScreenWidth = Math.round(vidRatio * winHeight);
      $fbPlayer.attr('data-width', fullScreenWidth);
    }
  }
};

function doStuff(platform) {
  var example = "toto";
  // 7行通用代码
  
  // 执行对应平台的差异化逻辑
  platformConfigs[platform].afterCommonLogic();
  
  resizeScale = 1;
}

// 入口函数保持不变
function doStuffForFacebook() {
  doStuff('facebook');
}

function doStuffForYoutube() {
  doStuff('youtube');
}

选择建议

  • 若当前仅两个平台、差异代码极少:优先选方案一,维护成本最低,新人接手也能快速理解;
  • 若差异逻辑可能单独复用,或喜欢函数式编程:选方案二,灵活度更高;
  • 若未来有扩展多平台的计划:选方案三,符合代码设计的开闭原则,扩展性拉满。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 06:46:27