关于前端version排序

217 阅读2分钟

前言

最近遇到需求,要对版本号进行排序,分享下处理方法。

版本号规则介绍

版本号通常由三部分组成 MAJOR.MINOR.PATCH 既主版本号.次版本号.修订号

方法1:按上面介绍的版本号规则我们可以按位置分别比较

代码如下

const versions = ["1.2.3", "1.10.2", "1.2.4", "1.3.0", "2.0.0", "1.2.10"];

versions.sort((a, b) => {
    const [majorA, minorA, patchA] = a.split('.').map(Number);
    const [majorB, minorB, patchB] = b.split('.').map(Number);
    if (majorA !== majorB) {
        return majorA - majorB;
    }
    if (minorA !== minorB) {
        return minorA - minorB;
    }
    return patchA - patchB;
})
// ["1.2.3", "1.2.4", "1.2.10", "1.3.0", "1.10.2", "2.0.0"]

上面函数很好理解,就是按主版本号、次版本号、修订号顺序依次对比,然后返回值就可以了。
但是这种方法会有问题,版本号不一定都纯 数字化字符串。比如:'v1.1.1'这样的版本号也很常见,如果是这样的版本号,那上面的函数就不行了。

const versions = ["1.2.3", "1.10.2", "1.2.4", "1.3.0", "2.0.0", "1.2.10"].map(v => `v${v}`);

versions.sort((a, b) => {
    const [majorA, minorA, patchA] = a.split('.').map(Number);
    const [majorB, minorB, patchB] = b.split('.').map(Number);
    if (majorA !== majorB) {
        return majorA - majorB;
    }
    if (minorA !== minorB) {
        return minorA - minorB;
    }
    return patchA - patchB;
})
// ['v1.2.3', 'v1.10.2', 'v1.2.4', 'v1.3.0', 'v2.0.0', 'v1.2.10']

从上面结果看,排序就乱了,当时你也可以把版本号中的v replace掉,然后在使用上面的函数也可以。

方法2: 使用localeCompare

localeCompare() 方法返回一个数字,表示参考字符串在排序顺序中是在给定字符串之前、之后还是与之相同

具体语法看MDN文件就可以了,这里简单说下版本号排序逻辑

const versions = ["1.2.3", "1.10.2", "1.2.4", "1.3.0", "2.0.0", "1.2.10"];
versions.sort((a, b) => {
    return a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' })
})
//['1.2.3', '1.2.4', '1.2.10', '1.3.0', '1.10.2', '2.0.0']

再来看版本号前加上v后的结果

const versions = ["1.2.3", "1.10.2", "1.2.4", "1.3.0", "2.0.0", "1.2.10"].map(v => `v${v}`);
versions.sort((a, b) => {
    return a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' })
})
//['v1.2.3', 'v1.2.4', 'v1.2.10', 'v1.3.0', 'v1.10.2', 'v2.0.0']

从结果上看,排序正常了

关于localeCompare第三个参数

这里的 localeCompare 使用了 { numeric: true, sensitivity: 'base' } 作为第三个参数,下面解释这两个属性:

1. numeric: true

numeric 选项用于数字感知比较。当设置为 true 时,localeCompare 会将字符串中的数字视为实际数值,而不是逐字符比较。这样可以确保版本号中的数字部分按照数值大小排序,而不是按字符串的字典顺序。对于字符串前面加v的情况,localeCompare 会先对字母部分进行比较。然后在处理numeric: true逻辑。

例如:

  • "v1.2.10" 会排在 "v1.10.2" 之前,而不是 "v1.2.3"
  • 如果 numeric: false 或没有指定,则 "v1.10.2" 会被认为小于 "v1.2.10",因为字符 "1" 小于字符 "2"。
2. sensitivity: 'base'

sensitivity 选项决定了字符串比较的敏感度。base 表示在比较时忽略大小写和一些特殊字符的差异,只关注字母和数字的基本差异。

  • 'base' :忽略大小写和字符的变音符号差异(例如 "a" 等同于 "A"、"ä" 等同于 "a")。
  • 'accent' :区分变音符号,但忽略大小写(例如 "a" 不同于 "ä",但 "a" 等同于 "A")。
  • 'case' :区分大小写,但忽略变音符号(例如 "a" 不同于 "A",但 "a" 等同于 "ä")。
  • 'variant' :区分大小写和变音符号(例如 "a" 不同于 "ä" 也不同于 "A")。

总结

以上两种方法我认为localeCompare比较简单,当然这个函数功能非常的强大,有兴趣的可以看下MDN