js小白模擬系列:模擬數(shù)組 reverse,sort,push,pop,shift,unshift,splice

這幾個函數(shù)的特征是,更改原數(shù)組.

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;
     }
這里默認(rèn)是升序.
但sort是可以接收一個函數(shù)的.函數(shù)按冒泡接收兩個參數(shù).

版本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;
     }

然后突然發(fā)現(xiàn) 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);
        
     }

真是投機(jī)取巧,,
不過怎么弄都無法用這種方法,傳 fn 模擬.能力有限,
個人感覺不可能,而且快速排序這種方式,似乎無法返回原來的數(shù)組?

版本4.0

我發(fā)現(xiàn)原生的排序是這樣的
先第一個和第二個比,依次類推,如果不滿足條件 則一直向右比
  如果 滿足條件 則從該位開始 向左比,直到不滿足條件時,回到向右比.
我也覺得說的不是人話..

反正下面這個版本能基本模擬,

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相比,數(shù)組當(dāng)中有引用值的時候,排序結(jié)果會不一樣.


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
     }

勉強(qiáng)做到了兩個參數(shù),

版本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];// 截取 ,, 我實在是無法全都放進(jìn)一個循環(huán),這個只能摘出來了.
               }
               
      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
     }

費(fèi)了這么長時間, 寫得還很丑..
教訓(xùn):
1.思路最重要
2.應(yīng)該先從數(shù)學(xué)上把關(guān)系理清楚
3.光抽象推理,覺得沒問題,但確實有問題,
    就不要徒勞耗費(fèi)腦細(xì)胞,用具體數(shù)據(jù),一步一步模擬處理步驟,更省時間.....
4.覺得好浪費(fèi)時間的時候, 實際上可以考慮先干點別的,55555555

思路:
第一個突破思路是,我把數(shù)據(jù)看成了三個片段
截取片段
截入片段
以及剩余最后片段.
下面是我思考過程的一種痕跡?
//   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
//             我們只進(jìn)行賦值操作

有了思路之后最費(fèi)時間的是哪里?  
一個是處理邊界,i值設(shè)定的時候,差一點輸出就差幾千里.
這個時候抽象邏輯思維我覺得沒什么大用,真的傷腦細(xì)胞,
這個時候最簡單的方法是,用一個數(shù)據(jù)模擬走一遍更有用.

還有一個費(fèi)時間的是有個坑,
我只想著在中間片段被賦值覆蓋前,要先進(jìn)行最后片段的賦值,
沒想到 b > argsLen 的時候,賦值順序應(yīng)該反過來.


最后一個教訓(xùn)是,
無論是理清楚數(shù)學(xué)上的邏輯關(guān)系,
還是其他邏輯關(guān)系,
都只盯著代碼是沒有效率的.(因為還是要靠想象力,)
也許我們應(yīng)該借助類似畫圖工具(這樣能節(jié)省想象所需耗費(fèi)的能量)

網(wǎng)上找到一個模擬方法,不過用了一些數(shù)組方法

使用js實現(xiàn)splice方法

===================================
2018/11/5
重新練習(xí)了一遍
發(fā)現(xiàn)之前我寫的,我自己都看不懂了.感覺當(dāng)時應(yīng)該挺用腦子了的,哈哈.

        <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) {
                      // 這里花了點時間. 負(fù)數(shù)本身的布爾值不是false
                        var temp = self[i];
                        self[i] = self[j];
                        self[j] = temp;
                    }
                  }
                }
                return self;
            }
            
            
        </script>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容