imooc《JavaScript深入浅出》上的一个 arraysSimilar 函数

任务
请在 index.html 文件中,编写 arraysSimilar 函数,实现判断传入的两个数组是否相似。具体需求:

  1. 数组中的成员类型相同,顺序可以不同。例如 [1, true] 与 [false, 2] 是相似的。
  2. 数组的长度一致。
  3. 类型的判断范围,需要区分: String , Boolean, Number, undefined, null, 函数, 日期, window.
    当以上全部满足,则返回"判定结果:通过",否则返回"判定结果:不通过"。

这是一个奇怪的需求,主要是要求“相似”的判断。

  • 第一直觉是直接对数组排序,然后比较类型。但由于 JS 比较大小的特性,这是不对的。
  • 那么需要变换一下,我这里是取每个元素的类型名简写,这样可以近似 \(O(NlogN)\) 排字典序,再将其作为整个数组的 typo ,就可以近似 \(O(N)\) 比较数组是否相似。
  • 第二个要注意的点是对无效参数的判断,一开始是用 == null 来判断 nullundefined 的,但是要求参数类型为数组,所以用 instanceof 判断。
  • 获取类型的替代方案是用 Object.prototype.toString() ,可以准确地拿到原型链上对象的类名,但是函数可能会被重写,所以不优先使用。
  • 但其实使用 instanceof 是有问题的,考虑不同页面的构造函数可以不同——因此判断数组可以用 Array.isArray() 代替,参考
        /* 
         * param1 Array 
         * param2 Array
         * return true or false
         */
        function arraysSimilar(arr1, arr2) {
            // 获取单个元素的类型名简写,已经满足需求
            // 替代方案:考虑用 Object.prototype.toString ,但会被 hack
            function getTypeNameS(item) {
                if (item === null)
                    return 'nl';
                else if (item instanceof Date)
                    return 'd';
                else if (item instanceof Window)
                    return 'w';
                else
                    return (typeof item)[0];
            }
            // 获取整个数组排序后的 typo
            function getArrayTypo(arr) {
                return arr.map(function (item) {
                    return getTypeNameS(item);
                }).sort().join('');
            }
            // 可以判断 == null ,但由于要求类型为数组,那就用 instanceof
            if (!(arr1 instanceof Array) || !(arr2 instanceof Array))
                return false;
            // 长度不等的情况,也可以合并到 typo 比较中
            if (arr1.length != arr2.length)
                return false;
            // 对于 typo 使用内置的字符串比较
            return getArrayTypo(arr1) == getArrayTypo(arr2);
        }

下面是另一种实现:

        function arraysSimilar(arr1, arr2) {
            // 用 Object.prototype.toString ,但会被 hack
            function getTypeName(item) {
                return item === null ? 'Null' : Object.prototype.toString.call(item).slice(8, -1);
            }
            
            // 获取整个数组排序后的 typo
            function getArrayTypo(arr) {
                return arr.map(function (item) {
                    return getTypeName(item);
                }).sort().join('');
            }
            
            // 使用 ECMAScript 5.1 的 isArray() 函数
            if (!Array.isArray(arr1) || !Array.isArray(arr2))
                return false;
            // 长度不等的情况
            if (arr1.length != arr2.length)
                return false;
            // 对于 typo 使用内置的字符串比较
            return getArrayTypo(arr1) == getArrayTypo(arr2);
        }




本文基于知识共享许可协议知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议发布,欢迎引用、转载或演绎,但是必须保留本文的署名BlackStorm以及本文链接http://www.cnblogs.com/BlackStorm/p/7182227.html,且未经许可不能用于商业目的。如有疑问或授权协商请与我联系

posted @ 2017-07-15 11:54  BlackStorm  阅读(...)  评论(... 编辑 收藏