最近在参与部门的app 重构,其中有一个是根据后台版本配置与当前 app 版本的表来提示用户是否有新版本,需要更新的提示。然后发现旧的代码直接使用的字符串比较:
const v1 = '1.0.1';
const v2 = '1.0.2';
console.log(v1 > v2); // false
乍一看,好像没问什么问题。但是当出现下面版本时,问题就来了:
const v1 = '1.2.1';
const v2 = '1.12.1';
console.log(v1 > v2); // true
其实这就涉及到了字符串的比较规则,字符串比较是使用基于标准字典的 Unicode 值来进行比较的。
'2' > '1' // true
'abc' > 'acb' // false
// 数字比较
2 > 11 // false
// 字符串比较
'2' > '11' // true
之所以出现 '2' > '11' 为真的情况,字符串比较的情况下会逐个字符进行比较。
'2'.charCodeAt(0) // 50
'11'.charCodeAt(0) // 49
这样比较,就会出现 '2' > '11' 为 true的情况。
回归到最初的问题,那么 app 版本比较的思路就有了。
补位方法:
既然字符串比较是逐位进行比较的,那么我们就假定主副补丁版本的最高位数为4,不足四位的左侧补齐0。
function toNum(version) {
const versionArr = version.split('.');
const num_place = ['0000', '000', '00', '0', ''];
const len = versionArr.length;
for (let i = 0; i < len; i++) {
const itemLen = versionArr[i].length;
versionArr[i] = num_place[itemLen] + versionArr[i];
}
const res = versionArr.join('');
return res;
};
function compareVersion(a, b) {
const version_a = toNum(a);
const version_b = toNum(b);
console.log(version_a);
return version_a > version_b;
}
console.log(compareVersion('1.0.1', '1.1.2')); // false
console.log(compareVersion('0.0.1', '0.0.2')); // false
console.log(compareVersion('1.1.0', '1.2.0')); // false
console.log(compareVersion('1.2.1', '1.12.1')); // false
console.log(compareVersion('1.1.12', '1.2')); // false
数值比较
分别对 主,副,补丁版本的数值进行比较:
function compareVersion(v1, v2) {
const v1arr = v1.split('.');
const v2arr = v2.split('.');
const len1 = v1arr.length;
const len2 = v2arr.length;
const max = len1 > len2 ? len1 : len2;
let i = 0;
for(; i < max; i++) {
const v1v = v1arr[i] ? parseInt(v1arr[i]) : 0;
const v2v = v2arr[i] ? parseInt(v2arr[i]) : 0;
if (v2v > v1v) {
return false;
}
}
if (v1arr.join() === v2arr.join()) {
return false;
}
return true;
}
console.log(compareVersion('1.0.1', '1.1.2')); // false
console.log(compareVersion('0.0.1', '0.0.2')); // false
console.log(compareVersion('1.1.0', '1.2.0')); // false
console.log(compareVersion('1.2.1', '1.12.1')); // false
console.log(compareVersion('1.1.12', '1.2')); // false