JavaScript版本号大小比较

App的版本号"6.2.3"跟"10.5.6"比较,那个比较大呢?这个问题相信移动端的原生开发同学一定不会陌生,那么在JavaScript中如何处理类似的问题呢?

最近在RN的开发过程中遇到了一个问题:由于RN中调用了原生模块的某个功能,但是该功能只在大于等于特定版本号的APP中才提供支持。
所以需要在JS代码中获取宿主APP的版本号,然后根据版本号的大小来进行适配。这样就面临着一个用JS代码进行版本号大小的比较的问题。

iOS原生(Objective-C)方案

我们知道在原生开发中,例如iOS开发(笔者是iOS开发出身)中,OC中的字符串对象NSString有着丰富的API来支持字符串的各种处理,其中就包括类似这种版本号比较大小的API。
例如做过iOS系统版本兼容适配的同学可能会见过下面这一组快捷系统版本号比较大小的宏定义:

//System Versioning Preprocessor Macros /
#define SYSTEM_VERSION_EQUAL_TO(v)                  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
#define SYSTEM_VERSION_GREATER_THAN(v)              ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v)                 ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v)     ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)


//适配iOS7
#define IOS7_OR_LATER   SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0")
//适配iOS8
#define IOS8_OR_LATER   SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")
//适配iOS10
#define IOS10_OR_LATER   SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"10.0")

上面代码中的 IOS7_OR_LATERIOS8_OR_LATER 宏定义就可以用来快速的判断当前系统的iOS版本版本号是否是iOS7及以上、iOS8及以上。
例如: iOS7.1.0 版本上IOS7_OR_LATER的返回是trueIOS8_OR_LATER的返回是false

上面的宏定义,实际上是用到了NSString类提供的字符串比较的API:

- (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask;

//使用方法如下

NSString *curOSVersionStr = [UIDevice currentDevice].systemVersion;
NSComparisonResult cmpResult = [curOSVersionStr compare:@"7.0" options:NSNumericSearch];
//mask选用的是NSNumericSearch,
//NSNumericSearch的说明如下
NSNumericSearch = 64,       /* Added in 10.2; Numbers within strings are compared using numeric value, that is, Foo2.txt < Foo7.txt < Foo25.txt; only applies to compare methods, not find */

可以看出,系统提供的这个字符串比较的参数选项就是用来处理类似版本号的比较场景的,是不是非常方便。

JavaScript的方案

回到正题,JavaScript语言貌似没有提供这种直接的API,仅有的String比较API完全不能满足这种需求。于是当然第一反应google一下,结果搜索到了不少文章,但是大多数文章中介绍的方法不是代码冗杂就是适应场景很有限,而且不少还有明显逻辑错误,于是决定自己写一个。不多说,直接上代码

//版本号比较
export const versionStringCompare = (preVersion='', lastVersion='') => {
    var sources = preVersion.split('.');
    var dests = lastVersion.split('.');
    var maxL = Math.max(sources.length, dests.length);
    var result = 0;
    for (let i = 0; i < maxL; i++) {  
        let preValue = sources.length>i ? sources[i]:0;
        let preNum = isNaN(Number(preValue)) ? preValue.charCodeAt() : Number(preValue);
        let lastValue = dests.length>i ? dests[i]:0;
        let lastNum =  isNaN(Number(lastValue)) ? lastValue.charCodeAt() : Number(lastValue);
        if (preNum < lastNum) {
            result = -1;
            break;
        } else if (preNum > lastNum) { 
            result = 1;
            break;
        }
    }
    return result;
}

//使用示例:
let result = versionStringCompare('1.0.2', '1.0');
console.log(result);    //1

let result = versionStringCompare('1.0.0', '1.1');
console.log(result);    //-1

let result = versionStringCompare('11.0.2', '5.5.6');
console.log(result);    //1

let result = versionStringCompare('5.5.0', '5.5');
console.log(result);    //0

let result = versionStringCompare('1.1.a', '1.1.1');
console.log(result);    //1

以上代码基本上兼容了各种常见的版本格式,而且代码简洁,判断结果比较符合常规思维,亲测运行结果符合预期,欢迎使用。

推荐阅读更多精彩内容