<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          模擬實(shí)現(xiàn) Array.prototype.splice

          共 4082字,需瀏覽 9分鐘

           ·

          2021-01-19 09:27

          splice

          array.splice(start[,?deleteCount[,?item1[,?item2[,?...]]]])

          MDN:splice()?方法通過(guò)刪除或替換現(xiàn)有元素或者原地添加新的元素來(lái)修改數(shù)組,并以數(shù)組形式返回被修改的內(nèi)容。此方法會(huì)改變?cè)瓟?shù)組

          Array.prototype.splice() 的用法如下:

          • array.splice(start) :刪除數(shù)組中從下標(biāo) start 開(kāi)始(包含 start )的所有元素
          • array.splice(start, deleteCount) :刪除數(shù)組中從下標(biāo) start 開(kāi)始(包含 start )的 deleteCount 元素
          • array.splice(start, deleteCount, item1, item2, ...) :刪除數(shù)組中從下標(biāo) start 開(kāi)始(包含 start )的 deleteCount 元素,然后在相同位置上插入 item1, item2, ...

          特征包括如下:

          • start :可正可負(fù),正數(shù)表示從下標(biāo)為 start 的位置開(kāi)始修改,如果 start > array.length - 1 ,則表示從數(shù)組末尾處開(kāi)始修改;負(fù)數(shù)表示從數(shù)組末位開(kāi)始的第幾位(從-1計(jì)數(shù),這意味著-n是倒數(shù)第n個(gè)元素并且等價(jià)于array.length-n
          • deleteCount :表示從 start 開(kāi)始要移除的元素個(gè)數(shù),省略則表示把 start 之后的所有元素都移除,如果是 0 或負(fù)數(shù),則不移除元素
          • item1, item2, ... :要添加進(jìn)數(shù)組的元素,從start?位置開(kāi)始。如果不指定,則?splice()?將只刪除數(shù)組元素
          • 返回:被刪除的元素組成的一個(gè)數(shù)組

          實(shí)現(xiàn)思路:

          • 處理 start 負(fù)數(shù)或超出邊界問(wèn)題,計(jì)算真實(shí)有效的開(kāi)始位置 startIndex

          • 處理 deleteCount 負(fù)數(shù)問(wèn)題,計(jì)算真實(shí)有效的刪除元素個(gè)數(shù) delCount

          • startIndex 開(kāi)始刪除 delCount 個(gè)元素并原地添加 item1, item2, … (添加元素個(gè)數(shù)為 addCount

            • 如果 delCount < addCount (刪除的元素個(gè)數(shù)小于添加元素):將數(shù)組中 startIndex + delCount 后的元素向后移動(dòng) addCount - delCount 個(gè)位置,將元素拷貝進(jìn)來(lái)
            • 如果 delCount = addCount (刪除的元素個(gè)數(shù)等于添加元素):直接將添加元素覆蓋刪除元素即可
            • 拷貝刪除的 delCount 到新數(shù)組 deletedElements ,用于 array.splice 函數(shù)返回
            • 如果 delCount > addCount (刪除的元素個(gè)數(shù)大于添加元素):將數(shù)組中 startIndex + delCount 后的元素向前移動(dòng) delCount - addCount 個(gè)位置,將添加元素拷貝進(jìn)來(lái)
          • 返回 deletedElements

          代碼實(shí)現(xiàn):

          Array.prototype._splice?=?function(start,?deleteCount)?{
          ????//?入?yún)⒃貍€(gè)數(shù)
          ????let?argumentsLen?=?arguments.length
          ????//?數(shù)組
          ????let?array?=?Object(this)
          ????//?數(shù)組長(zhǎng)度
          ????let?len?=?array.length
          ????//?添加元素個(gè)數(shù)
          ????let?addCount?=?argumentsLen?>?2???argumentsLen?-2?:?0
          ????//?計(jì)算有效的?start
          ????let?startIndex?=?computeSpliceStartIndex(start,?array)
          ????//?計(jì)算有效的?deleteCount
          ????let?delCount?=?computeSpliceDeleteCount(startIndex,?deleteCount,?len)
          ????//?記錄刪除的數(shù)組元素
          ????let?deletedElements?=?new?Array(delCount)
          ????
          ????//?將待刪除元素記錄到?deletedArray
          ????recordDeleteElements(startIndex,?delCount,?array,?deletedElements)
          ????
          ????//?移動(dòng)數(shù)組元素
          ????moveElements(startIndex,?delCount,?array,?addCount)
          ????
          ????let?i?=?startIndex
          ????let?argumentsIndex?=?2
          ????
          ????//?插入新元素
          ????while?(argumentsIndex?????????array[i++]?=?arguments[argumentsIndex++]
          ????}
          ????
          ????array.length?=?len?-?delCount?+?addCount

          ????//?返回刪除元素?cái)?shù)組
          ????return?deletedElements;
          }

          //?計(jì)算真實(shí)的?start
          function?computeSpliceStartIndex(start,?len)?{
          ????//?處理負(fù)值,如果負(fù)數(shù)的絕對(duì)值大于數(shù)組的長(zhǎng)度,則表示開(kāi)始位置為第0位
          ????if(start?0)?{
          ????????start?+=?len
          ????????return?start?0???0?:?start
          ????}
          ????//?處理超出邊界問(wèn)題
          ????return?start?>?len?-?1???len?-?1:?start
          }?

          //?計(jì)算真實(shí)的?deleteCount
          function?computeSpliceDeleteCount(startIndex,?deleteCount,?len)?{
          ????//?超出邊界問(wèn)題
          ????if(deleteCount?>?len?-?startIndex)?deleteCount?=?len?-?startIndex
          ????//?負(fù)值問(wèn)題
          ????if(deleteCount?0)?deleteCount?=?0
          ????return?deleteCount
          }

          //?記錄刪除元素,用于?Array.prototype.splice()?返回
          function?recordDeleteElements(startIndex,?delCount,?array,?deletedElementd)?{
          ????for(let?i?=?0;?i?????????deletedElementd[i]?=?array[startIndex?+?i]
          ????}
          }

          //?移動(dòng)數(shù)組元素,便于插入新元素
          function?moveElements(startIndex,?delCount,?array,?addCount)?{
          ????let?over?=?addCount?-?delCount
          ????if(over)?{
          ????????//?向后移
          ????????for(let?i?=?array.length?-?1;?i?>=?startIndex?+?delCount;?i--)?{
          ????????????array[i+over]?=?array[i]
          ????????}
          ????}?else?if?(over?0)?{
          ????????//?向前移
          ????????for(let?i?=?startIndex?+?delCount;?i?<=?array.length?-?1;?i++)?{
          ????????????if(i?+?Math.abs(over)?>?array.length?-?1)?{
          ????????????????//?刪除冗于元素
          ????????????????delete?array[i]
          ????????????????continue
          ????????????}
          ????????????array[i]?=?array[i?+?Math.abs(over)]
          ????????}
          ????}
          }

          let?months?=?['Jan',?'March',?'April',?'June']
          console.log(months._splice(1,?1,?'Feb'))
          //?["March"]
          console.log(months)
          //?["Jan",?"Feb",?"April",?"June"]

          補(bǔ)充:密封對(duì)象與凍結(jié)對(duì)象

          密封對(duì)象:通常一個(gè)對(duì)象是可擴(kuò)展的(可以添加新的屬性)。密封一個(gè)對(duì)象會(huì)讓這個(gè)對(duì)象變的不能添加新屬性,且所有已有屬性會(huì)變的不可配置。屬性不可配置的效果就是屬性變的不可刪除,以及一個(gè)數(shù)據(jù)屬性不能被重新定義成為訪(fǎng)問(wèn)器屬性,或者反之。但屬性的值仍然可以修改。嘗試刪除一個(gè)密封對(duì)象的屬性或者將某個(gè)密封對(duì)象的屬性從數(shù)據(jù)屬性轉(zhuǎn)換成訪(fǎng)問(wèn)器屬性,結(jié)果會(huì)靜默失敗或拋出TypeError(在嚴(yán)格模式?中最常見(jiàn)的,但不唯一)

          --MDN

          if(delCount?!==?addCount?&&?Object.isSealed(array))?{
          ????throw?new?TypeError('the?array?is?sealed')
          }

          凍結(jié)對(duì)象:數(shù)組作為一種對(duì)象,被凍結(jié),其元素不能被修改。沒(méi)有數(shù)組元素可以被添加或移除。

          --MDN

          if(delCount?>?0?&&?addCount?>?0?&&?Object.isFrozen(array))?{
          ????throw?new?TypeError('the?array?is?frozen')
          }

          V8源碼

          function?ArraySplice(start,?delete_count)?{
          ??CHECK_OBJECT_COERCIBLE(this,?"Array.prototype.splice");
          ????
          ??//?參數(shù)
          ??var?num_arguments?=?arguments.length;
          ??//?數(shù)組
          ??var?array?=?TO_OBJECT(this);
          ??//?數(shù)組長(zhǎng)度
          ??var?len?=?TO_LENGTH(array.length);
          ??//?計(jì)算有效的?start_i
          ??var?start_i?=?ComputeSpliceStartIndex(TO_INTEGER(start),?len);
          ??//?計(jì)算有效的?del_count
          ??var?del_count?=?ComputeSpliceDeleteCount(delete_count,?num_arguments,?len,
          ???????????????????????????????????????????start_i);
          ??//?返回?cái)?shù)組
          ??var?deleted_elements?=?ArraySpeciesCreate(array,?del_count);
          ??deleted_elements.length?=?del_count;
          ??//?添加元素個(gè)數(shù)
          ??var?num_elements_to_add?=?num_arguments?>?2???num_arguments?-?2?:?0;
          ????
          ??//?如果是密封對(duì)象且刪除元素個(gè)數(shù)與添加元素個(gè)數(shù)不一致,報(bào)錯(cuò)
          ??if?(del_count?!=?num_elements_to_add?&&?%object_is_sealed(array))?{
          ????throw?%make_type_error(kArrayFunctionsOnSealed);
          ??}?else?if?(del_count?>?0?&&?%object_is_frozen(array))?{
          ????//?如果是凍結(jié)對(duì)象且刪除元素個(gè)數(shù)大于0,報(bào)錯(cuò)
          ????throw?%make_type_error(kArrayFunctionsOnFrozen);
          ??}
          ????
          ??//?計(jì)算變更元素
          ??var?changed_elements?=?del_count;
          ??if?(num_elements_to_add?!=?del_count)?{
          ????//?If?the?slice?needs?to?do?a?actually?move?elements?after?the?insertion
          ????//?point,?then?include?those?in?the?estimate?of?changed?elements.
          ????changed_elements?+=?len?-?start_i?-?del_count;
          ??}
          ????
          ??//?移動(dòng)元素
          ??if?(UseSparseVariant(array,?len,?IS_ARRAY(array),?changed_elements))?{
          ????%NormalizeElements(array);
          ????if?(IS_ARRAY(deleted_elements))?%NormalizeElements(deleted_elements);
          ????SparseSlice(array,?start_i,?del_count,?len,?deleted_elements);
          ????SparseMove(array,?start_i,?del_count,?len,?num_elements_to_add);
          ??}?else?{
          ????SimpleSlice(array,?start_i,?del_count,?len,?deleted_elements);
          ????SimpleMove(array,?start_i,?del_count,?len,?num_elements_to_add);
          ??}

          ??//?將添加元素插入到刪除元素的位置
          ??var?i?=?start_i;
          ??var?arguments_index?=?2;
          ??var?arguments_length?=?arguments.length;
          ??while?(arguments_index?????array[i++]?=?arguments[arguments_index++];
          ??}
          ??array.length?=?len?-?del_count?+?num_elements_to_add;

          ??//?Return?the?deleted?elements.
          ??return?deleted_elements;
          }

          Array.prototype.splice源碼地址

          總結(jié)

          splice 實(shí)現(xiàn)原理很簡(jiǎn)單,核心就是移動(dòng)刪除元素的邊界,使無(wú)效元素個(gè)數(shù)與添加元素個(gè)數(shù)一致,然后用添加元素覆蓋進(jìn)去, 注意 ?splice 是原地操作,不創(chuàng)建新數(shù)組,需要判讀數(shù)組是否被密封或凍結(jié)

          完整代碼實(shí)現(xiàn)

          Array.prototype._splice?=?function(start,?deleteCount)?{
          ????//?入?yún)⒃貍€(gè)數(shù)
          ????let?argumentsLen?=?arguments.length
          ????//?數(shù)組
          ????let?array?=?Object(this)
          ????//?數(shù)組長(zhǎng)度
          ????let?len?=?array.length
          ????//?添加元素個(gè)數(shù)
          ????let?addCount?=?argumentsLen?>?2???argumentsLen?-2?:?0
          ????//?計(jì)算有效的?start
          ????let?startIndex?=?computeSpliceStartIndex(start,?array)
          ????//?計(jì)算有效的?deleteCount
          ????let?delCount?=?computeSpliceDeleteCount(startIndex,?deleteCount,?len)
          ????//?記錄刪除的數(shù)組元素
          ????let?deletedElements?=?new?Array(delCount)
          ????
          ????//?將待刪除元素記錄到?deletedArray
          ????recordDeleteElements(startIndex,?delCount,?array,?deletedElements)
          ????
          ????//?密封對(duì)象
          ????if(delCount?!==?addCount?&&?Object.isSealed(array))?{
          ????????throw?new?TypeError('the?array?is?sealed')
          ????}
          ????//?凍結(jié)對(duì)象
          ????if(delCount?>?0?&&?addCount?>?0?&&?Object.isFrozen(array))?{
          ????????throw?new?TypeError('the?array?is?frozen')
          ????}
          ????
          ????//?移動(dòng)數(shù)組元素
          ????moveElements(startIndex,?delCount,?array,?addCount)
          ????
          ????let?i?=?startIndex
          ????let?argumentsIndex?=?2
          ????
          ????//?插入新元素
          ????while?(argumentsIndex?????????array[i++]?=?arguments[argumentsIndex++]
          ????}
          ????
          ????array.length?=?len?-?delCount?+?addCount

          ????//?返回刪除元素?cái)?shù)組
          ????return?deletedElements;
          }

          //?計(jì)算真實(shí)的?start
          function?computeSpliceStartIndex(start,?len)?{
          ????//?處理負(fù)值,如果負(fù)數(shù)的絕對(duì)值大于數(shù)組的長(zhǎng)度,則表示開(kāi)始位置為第0位
          ????if(start?0)?{
          ????????start?+=?len
          ????????return?start?0???0?:?start
          ????}
          ????//?處理超出邊界問(wèn)題
          ????return?start?>?len?-?1???len?-?1:?start
          }?

          //?計(jì)算真實(shí)的?deleteCount
          function?computeSpliceDeleteCount(startIndex,?deleteCount,?len)?{
          ????//?超出邊界問(wèn)題
          ????if(deleteCount?>?len?-?startIndex)?deleteCount?=?len?-?startIndex
          ????//?負(fù)值問(wèn)題
          ????if(deleteCount?0)?deleteCount?=?0
          ????return?deleteCount
          }

          //?記錄刪除元素,用于?Array.prototype.splice()?返回
          function?recordDeleteElements(startIndex,?delCount,?array,?deletedElementd)?{
          ????for(let?i?=?0;?i?????????deletedElementd[i]?=?array[startIndex?+?i]
          ????}
          }

          //?移動(dòng)數(shù)組元素,便于插入新元素
          function?moveElements(startIndex,?delCount,?array,?addCount)?{
          ????let?over?=?addCount?-?delCount
          ????if(over)?{
          ????????//?向后移
          ????????for(let?i?=?array.length?-?1;?i?>=?startIndex?+?delCount;?i--)?{
          ????????????array[i+over]?=?array[i]
          ????????}
          ????}?else?if?(over?0)?{
          ????????//?向前移
          ????????for(let?i?=?startIndex?+?delCount;?i?<=?array.length?-?1;?i++)?{
          ????????????if(i?+?Math.abs(over)?>?array.length?-?1)?{
          ????????????????//?刪除冗于元素
          ????????????????delete?array[i]
          ????????????????continue
          ????????????}
          ????????????array[i]?=?array[i?+?Math.abs(over)]
          ????????}
          ????}
          }

          const?months?=?['Jan',?'March',?'April',?'June']
          console.log(months._splice(1,?0,?'Feb'))
          //?[]
          console.log(months)
          //?["Jan",?"Feb",?"March",?"April",?"June"]

          console.log(months._splice(4,?1,?'May'))
          //?["June"]
          console.log(months)
          //?["Jan",?"Feb",?"March",?"April",?"May"]

          最后

          歡迎關(guān)注「三分鐘學(xué)前端」,回復(fù)「交流」自動(dòng)加入前端三分鐘進(jìn)階群,每日一道編程算法面試題(含解答),助力你成為更優(yōu)秀的前端開(kāi)發(fā)!

          》》面試官也在看的前端面試資料《《
          “在看和轉(zhuǎn)發(fā)”就是最大的支持
          瀏覽 70
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  无码123区 | 日韩精品在线一二三四五区 | 农村嫩苞一区二区三区… | 欧美熟妇精品黑人巨大一二三区 | 精品免费黄色视频 |