js小白模拟系列:模拟数组 reverse,sort,push,pop,shift,unshift,splice

这几个函数的特征是,更改原数组.

reverse

Array.prototype.reverse = function () {
      var arr = this;
      var len = arr.length - 1;
      for(var i = 0; i < Math.floor(len / 2);i++) {
        var temp = arr[i];
        arr[i] = arr[len - i];
        arr[len - i] = temp;
      }
      return arr;
     }
这你就明白,两个变量互相换是多么重要的方法了吧

sort
版本1.0

Array.prototype.sort = function () {
        var arr = this;
        var len = arr.length;
        for(var i = 0; i < len - 1; i++) {
          for(var j = i + 1; j < len ; j++){
            if(arr[i] > arr[j]) {
              var temp = arr[i];
                  arr[i] = arr[j];
                  arr[j] = temp;
            }
          }
        }
        return arr;
     }
这里默认是升序.
但sort是可以接收一个函数的.函数按冒泡接收两个参数.

版本2.0

Array.prototype.sort = function (fn) {
        var arr = this;
        var len = arr.length;
        for(var i = 0; i < len - 1; i++) {
          for(var j = i + 1; j < len ; j++){
            if(fn ? fn(arr[i],arr[j]) > 0 : arr[i] > arr[j]){
              console.log(fn(arr[i],arr[j]),'aaa');
              var temp = arr[i];
                  arr[i] = arr[j];
                  arr[j] = temp;
            }
          }
        }
        return arr;
     }

然后突然发现 sort原生方法的遍历跟我们的稍微不同.好像是快速排序?

版本3.0

先回忆一下快速排序
function sort (arr) {
       var len = arr.length;
       if(len <= 1) {
         return arr;
       }
       var left = [];
       var right = [];
       var p = arr[0];
       var mid = [p];
       for(var i = 1;i < len;i++){
         if(arr[i] < p) {
           left.push(arr[i]);
         }else {
           right.push(arr[i]);
         }
       }
       return sort(left).concat(mid,sort(right));
     }

然后改放在原型链上

Array.prototype.sort = function () {
        var arr = this;
        
        function sort1 (arr) {
       var len = arr.length;
       if(len <= 1) {
         return arr;
       }
       var left = [];
       var right = [];
       var p = arr[0];
       var mid = [p];
       for(var i = 1;i < len;i++){
         if(arr[i] < p) {
           left.push(arr[i]);
         }else if(arr[i] > p){
           right.push(arr[i]);
         }else {
            mid.push(arr[i])
          }
       }
       return sort1(left).concat(mid,sort1(right));
     }
        
        return sort1(arr);
        
     }

真是投机取巧,,
不过怎么弄都无法用这种方法,传 fn 模拟.能力有限,
个人感觉不可能,而且快速排序这种方式,似乎无法返回原来的数组?

版本4.0

我发现原生的排序是这样的
先第一个和第二个比,依次类推,如果不满足条件 则一直向右比
  如果 满足条件 则从该位开始 向左比,直到不满足条件时,回到向右比.
我也觉得说的不是人话..

反正下面这个版本能基本模拟,

Array.prototype.sort = function (fn) {
        var arr = this;
        var len = arr.length;
        for(var i = 0;i < len - 1;i++) {
          if(fn ? fn(arr[i],arr[i + 1]) > 0 : arr[i] > arr[i + 1]){//向右
            var temp = arr[i];
            arr[i] = arr[i + 1];
            arr[i + 1] = temp;
            for(var j = i;j >= 0;j--){
              if(fn ? fn(arr[j - 1],arr[j]) > 0 : arr[j - 1] > arr[j]) {//向左
                var temp = arr[j];
                    arr[j] = arr[j - 1];
                    arr[j - 1] = temp;
              }else {
                break// 这个省性能
              }
            }
          }
        }
        return arr;
     }

这几个跟原生sort相比,数组当中有引用值的时候,排序结果会不一样.


push

Array.prototype.push = function (a) {
      if(a === undefined){return this.length}
      var arr = this;
      arr[arr.length] = a;
      return arr.length;
     }

pop

Array.prototype.pop = function () {
      var arr = this;
      var len = arr.length;
      var last = arr[len - 1] || undefined;
      arr[len - 1] = undefined;
      arr.length = len - 1 <= 0 ? 0 : len - 1;
      return last
     }

shift

Array.prototype.shift = function () {
      var arr = this;
      var len = arr.length;
      var first = arr[0];
      for(var i = 0; i < len - 1;i ++){
        arr[i] = arr[i + 1];
      }
      arr[len - 1] = undefined;
      arr.length = len - 1 <= 0 ? 0 : len - 1;
      return first
     }

unshift

Array.prototype.unshift = function (a) {
      if(a === undefined){return this.length}
      var arr = this;
      var len = arr.length;
      for(var i = len;i >= 1 ;i--) {
        arr[i] = arr[i - 1];
      }
      arr[0] = a;
      
      return arr.length;
     }

splice 个人觉得这个挺难的,
版本1.0

Array.prototype.splice = function (a,b) {
      var arr = this;
      var len = arr.length;
      var newArr = [];
      var a = a < 0 ? len + a : a;
      for(var i = a;i < len; i++) {
        if(i < a + b) {
          newArr[i - a] = arr[i];// 筛选
        }
        if(i < len - b + 1){
          arr[i] = arr[i + b];// 移位
        }else {
          break
        }
      }
      arr.length = len - b;// 删除
      
      return newArr
     }

勉强做到了两个参数,

版本2.0

这个splice 用的时间比上面加起来的还要多.

Array.prototype.splice = function (a,b) {
      var arr = this;
      var newArr = [];
      var args = [].slice.call(arguments,2);
      var argsLen = args.length;
      var a = a < 0 ? len + a : a;
      var len = arr.length;
      var lastLen = len - b + argsLen;
       for(var i = a;i < a + b; i++) {
                 newArr[i - a] = arr[i];// 截取 ,, 我实在是无法全都放进一个循环,这个只能摘出来了.
               }
               
      if (b <= argsLen) {
               for(var i = lastLen - 1;i >= a;i--) {
                 if(i >= a + argsLen) {
                   arr[i] = arr[i -argsLen + b];// 最后片段
                 }else {
                   arr[i] = args[i - a];//中间片段
                 }
               }
      }else {
        for(var i = a;i < lastLen;i++){
          if(i < a + argsLen) {
            arr[i] = args[i - a];//中间片段
          }else{
            arr[i] = arr[i + b - argsLen];//最后片段
          }
        }
      }
      arr.length = len - b + argsLen;// 截取
      return newArr
     }

费了这么长时间, 写得还很丑..
教训:
1.思路最重要
2.应该先从数学上把关系理清楚
3.光抽象推理,觉得没问题,但确实有问题,
    就不要徒劳耗费脑细胞,用具体数据,一步一步模拟处理步骤,更省时间.....
4.觉得好浪费时间的时候, 实际上可以考虑先干点别的,55555555

思路:
第一个突破思路是,我把数据看成了三个片段
截取片段
截入片段
以及剩余最后片段.
下面是我思考过程的一种痕迹?
//   var arr = [1,2,5,8,3,4,6,7,9];len = 9
//             [5,8]b = 2
//             [11,22,33] argsLen = 3
//             [1,2,11,22,33,3,4,6,7,9]lastLen = 10
//             lastLen = len - b + argsLen = 9 - 2 + 3 = 10
//             最后一个片段 [3,4,6,7,9] a + argsLen = 2 + 3 === lastLen
//             中间片段 [11,22,33] a == a + argsLen
//             剪切片段[5,8] a == a + b
//             我们只进行赋值操作

有了思路之后最费时间的是哪里?  
一个是处理边界,i值设定的时候,差一点输出就差几千里.
这个时候抽象逻辑思维我觉得没什么大用,真的伤脑细胞,
这个时候最简单的方法是,用一个数据模拟走一遍更有用.

还有一个费时间的是有个坑,
我只想着在中间片段被赋值覆盖前,要先进行最后片段的赋值,
没想到 b > argsLen 的时候,赋值顺序应该反过来.


最后一个教训是,
无论是理清楚数学上的逻辑关系,
还是其他逻辑关系,
都只盯着代码是没有效率的.(因为还是要靠想象力,)
也许我们应该借助类似画图工具(这样能节省想象所需耗费的能量)

网上找到一个模拟方法,不过用了一些数组方法

使用js实现splice方法

===================================
2018/11/5
重新练习了一遍
发现之前我写的,我自己都看不懂了.感觉当时应该挺用脑子了的,哈哈.

        <script type="text/javascript">
            
            Array.prototype.myReverse = function () {
                var self = this;
                var arr = [];
                var len = self.length;
                var i = 0;
                while (len--){
                    arr[i++] = self[len];
                }
                return arr;
            }
            
            Array.prototype.myPush = function (item) {
                var self = this;
                var len = self.length;
                self[len] = item;
                return self.length;
            }
            
            Array.prototype.myPop = function () {
                var self = this;
                var len = self.length;
                var a = self[len - 1];
                self.length = len - 1;
                return a
            }
            Array.prototype.myUnshift = function (item) {
              var self = this;
              var len = self.length + 1;
              while (len--){
                if (len == 0) {
                    self[len] = item;
                } else {
                  self[len] = self[len - 1]
                }
              }
              return self.length;
            }
            Array.prototype.myShift = function () {
              var self = this;
              var len = self.length;
              var a = self[0];
              for(var i = 0; i < len - 1;i++) {
                self[i] = self[i + 1];
              }
              self.length = len - 1;
              return a;
            }
            Array.prototype.mySplice = function (a,b) {
              var self = this;
              var len = self.length;
              var args = [];
              var a = a > 0 ? a : len + a;
              for(var i = 2; i < arguments.length;i++) {
                args[i - 2] = arguments[i];
              }
              
              var arr1 = []; // 截取的
              
              for(var j = a; j < self.length; j++) {
                arr1[j - a] = self[j];
              }
              console.log(a);
              self.length = a;// 第一段.
              var arr2 = [];// 最后一段
              for(var k = b; k < arr1.length; k++) {
                arr2[k - b] = arr1[k];
              }
              
              arr1.length = len - a - b;// 截取要返回的.
              
              var len1 = self.length;
              var len2 = args.length;
              var len3 = arr2.length;
              
              // 拼接self
              for(var q = len1 ; q < len1 + len2 + len3; q++) {
                if (q < len2 + len1) {
                    self[q] = args[q - len1]
                }else {
                  self[q] = arr2[q - len1 - len2];
                }
              }
              return arr1;
              
            }
            
            Array.prototype.mySort = function (handle,context) {
              var context = context || window;
              function handle1 (a,b) {
                return a - b
              }
              var handle = handle || handle1;
                var self = this;
                var len = self.length;
                for(var i = 0; i < len - 1;i++) {
                  for(var j = i + 1; j < len; j++) {
                    if (handle.call(context,self[i],self[j]) >= 0) {
                      // 这里花了点时间. 负数本身的布尔值不是false
                        var temp = self[i];
                        self[i] = self[j];
                        self[j] = temp;
                    }
                  }
                }
                return self;
            }
            
            
        </script>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 230,527评论 6 544
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 99,687评论 3 429
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 178,640评论 0 383
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 63,957评论 1 318
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 72,682评论 6 413
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 56,011评论 1 329
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 44,009评论 3 449
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 43,183评论 0 290
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 49,714评论 1 336
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 41,435评论 3 359
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 43,665评论 1 374
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 39,148评论 5 365
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 44,838评论 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 35,251评论 0 28
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 36,588评论 1 295
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 52,379评论 3 400
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 48,627评论 2 380

推荐阅读更多精彩内容