zoukankan      html  css  js  c++  java
  • 基于原生JS封装数组原型上的sort方法

    基于原生JS封装数组原型上的sort方法

    最近学习了数组的原型上内置方法的封装,加强了用原生JS封装方法的能力,也进一步理解数组方法封装的过程,实现的功能。虽然没有深入底层,了解源码。以下解法都是基于个人理解用纯原生JS实现的功能。如有不对的地方,可以评论告诉我哟

    首先,我们先来看一下sort方法的作用、参数、以及方法的返回值,原有数组是否发生改变

    sort方法主要用于数组的排序
    参数分为两种:

    • 一种:传的参数是函数、 (排序主要看函数的返回值)
    • 另一种:传的不是函数、或者不传(只要传的不是函数就对原来排序过程不产生影响)
      方法的返回值是原来数组排序后的数组
      原来数组发生改变,是排序后的数组

    其次,我们来看一下sort方法要处理的各种情况之间的比较

    情况1:无参实现对字符串数组的排序
    情况2:无参实现对number类型的数组进行排序
    情况3:无参实现对字符串、number等混合类型的数组的排序
    情况4:带参实现对number类型的数值数据排序
    情况5:带参sort()对简单对象List的自定义属性排序
    情况6:带参实现对字符串、number混合类型的数组的排序

    sort方法对参数的处理:

    情况1:如果参数不是函数,则不影响原来排序过程
    情况2:如果参数是函数,则根据回调函数中的返回值进行排序。如果返回值大于0,则交换位置;如果返回值小于0,则不交换位置
    如果返回值不是一个数字,则不交换位置

    基于以上情况的讨论,sort方法实现的核心原理如下:

    核心原理:不带参(以及带的参数不是函数)的情况下:默认升序排列
    不带参的情况下,直接转字符串,逐个比较ASCII码的值
    只要有一个是对象{}就不交换
    带参数为函数的情况下:
    根据函数的返回值进行比较;如果函数返回值大于0;则交换位置

    实现代码如下:

    Array.prototype.mySort = function(fn){
        if(Object.prototype.toString.call(fn)==='[object Function]'){
            //如果传进来参数的是函数
            for(var i = 0;i<this.length-1;i++){
                //遍历数组,将前后两项作为实参传给fn
                if(fn.call(this,this[i],this[i+1])>0){
                    //如果fn执行之后的返回值大于0.就调用swap方法交换位置
                    var a = this[i],b=this[i+1];
                    this[i] = swap(a,b).a;
                    this[i+1] = swap(a,b).b;
                    //交换之后,如果当前项不是第一项,则当前项(索引为i的项)继续跟前面的项进行比较
                    if(i>0){
                        for(var j = i-1;j>=0;j--){
                                if(fn.call(this,this[j],this[j+1])>0){
                                    var a = this[j],b=this[j+1];
                                    this[j] = swap(a,b).a;
                                    this[j+1] = swap(a,b).b;
                                }
                            }
                    }
                }
            }
        }else{
            //如果不是函数,则按正常排序
            //遍历数组,将前后两项进行比较
            for(var i = 0;i<this.length-1;i++){
                var cur = this[i];//当前项
                var next = this[i+1];//下一项
                if(comASCII(cur,next)){
                    //当返回true的时候交换,并且交换完成之后,当前项继续往前比较
                    this[i] = swap(cur,next).a;
                    this[i+1] = swap(cur,next).b;
                    //当前项继续向前比较
                    if(i>0){
                        for(var k = i-1;k>=0;k--){
                            var cur = this[k];
                            var next = this[k+1];
                            if(comASCII(cur,next)){
                                this[k] = swap(cur,next).a;
                                this[k+1] = swap(cur,next).b;
                            }
                        }
                    }
                }
            }
        }
        //封装一个交换位置的函数
        function swap(a,b){
            return {
                a:b,
                b:a
            }
        }
        //如果不传参的情况下比较ASCII码
        function comASCII(cur,next){
            //全部转换为字符串、逐项比较ASCII码
            cur = cur.toString();
            next = next.toString();
            //取长度最大值
            var len = cur.length>next.length?next.length:cur.length;
            //当前后两项都不是不是{}类型的数据时,进行比较
            if(cur!=='[object Object]'&&next!=='[object Object]'){
                for(var j = 0;j<len;j++){
                    if(!isNaN(cur.charCodeAt(j))&&!isNaN(next.charCodeAt(j))){
                        //如果二者的ASCII码都是有效数字
                        if(cur.charCodeAt(j)>next.charCodeAt(j)){
                            //如果前一项比后一项当前的ASCII码大,则返回true,交换位置
                            return true;
                        }else if(cur.charCodeAt(j)==next.charCodeAt(j)){
                        //如果相等直接进入下一轮循环
                                continue;
                            }else{
                            //前项比后项小,直接返回false
                                return false;
                            }
                    }
                }
                if(!isNaN(cur.charCodeAt(len))&&isNaN(next.charCodeAt(len))&&(cur.charCodeAt(len-1)==next.charCodeAt(len-1))){
                    //比较完之后,如果前一项ASCII还是有效数字,说明前项比后项大,交换
                    return true;
                }
            }
            //如果上述条件不满足,则不交换
            return false;
        }
        //返回当前数组
        return this;
    };
    

    实验结果

    无参(参数非函数)对纯数字数组的排序

    带参对纯数字数组的排序(升序)

    带参对纯数字数组的排序(降序)

    无参(参数非函数)对纯字母字符串数组的排序

    带参(参数是函数)对纯字母字符串数组的排序(升序)

    带参(参数是函数)对纯字母字符串数组的排序(降序)

    无参(参数非函数)对纯字母字符串、数字字母组合字符串、纯数字字符串组合的排序

    带参(参数是函数)对纯字母字符串、纯数字、数字字母字符串、纯数字字符串等的组合排序结果(升序)

    带参(参数是函数)对纯字母字符串、纯数字、数字字母字符串、纯数字字符串等的组合排序结果(降序)

    无参(参数非函数)对纯字母字符串、纯数字、数字字母字符串、纯数字字符串等的组合排序结果

    带参(参数是函数)对纯字母字符串、纯数字、数字字母字符串、纯数字字符串等的组合排序结果(升序)

    带参(参数是函数)对纯字母字符串、纯数字、数字字母字符串、纯数字字符串等的组合排序结果(降序)

    无参(参数非函数)对数组、纯字母字符串、纯数字、数字字母字符串、纯数字字符串等的排序

    带参(参数是函数)对数组、纯字母字符串、纯数字、数字字母字符串、纯数字字符串等的排序(升序)

    带参(参数是函数)对数组、纯字母字符串、纯数字、数字字母字符串、纯数字字符串等的排序(降序)

    带参(参数是函数)对纯数组的排序(升序)

    带参(参数是函数)对纯数组的排序(降序)

    带参(参数是函数)对纯对象的排序(升序)

    带参(参数是函数)对纯对象的排序(降序)

  • 相关阅读:
    两个容器盛水法。
    Windows程序设计 读书笔记 位图和BitBlt。
    VC DrawText显示多行,包括设置行距。
    内存管理函数
    GDI+
    二进制法。
    Windows程序设计 读书笔记 打印机。
    逆推法
    DDB和DIB概念区别 及 程序示例。
    Windows程序设计 读书笔记 剪贴板。
  • 原文地址:https://www.cnblogs.com/kjz-jenny/p/9365115.html
Copyright © 2011-2022 走看看