是這樣的,我在做一個vue的添加刪除實例。

這裡我覺得傳進來的id應該就能直接通過id刪了。

為什麼還要這麼長這麼多代碼才能實現。。。

而且上面那個有bug。

其實我覺得直接:

this.list.splice(id,1);

這樣不就行了嗎,可為什麼不行,效果跟第一種代碼一模一樣。

我就不知道了,區別在哪。

或者說原理是什麼


額,你要是這樣子, 這邊建議先不要學vue, 先學好js好不好。


splice 是按索引去操作數組的,id 不一定是數組的索引。其實可以用 findIndex 找出第一個匹配 id 的索引,然後再 splice。


說明你對數組的splice()與some()還沒理解到位.

splice(pos,num,...items) 不講完整功能,只解釋你代碼里的.

第一個參數,表示要刪除數組元素的起始位置.你的id是表示數組索引,還是你列表(list)的條目id(如文章/評論id).是第二種,你就需要通過console下的方法來查詢該item在list的位置.拿到位置(i)後再刪除.

some()/every(),是一種優化策略.

如果用forEach/map等需要遍歷完數組的所有元素,some/every可以提前終止遍歷,不需要循環整個列表.可自己在some/forEach里console.log一下驗證

姑且以那行console為分界線,上方的是第一種,下方的是第二種吧.

首先,兩個方式的邏輯是不一樣的,第一種方式認為id這個形參是數組下標,第二種方式認為id是list這個對象數組中每個對象的一個屬性(第二種的可能性更高一些,畢竟這個形參叫id,而不是叫index)

其次第一種方法...看起來傻乎乎的,但確實不嚴格等價於`this.list.splice(id,1);`

splice函數的第一個參數,是可以為負的,且有實際含義,那種複雜的寫法,可以規避掉這種情況(當然,我們一般是不會這麼極端的,因為這個del函數的調用一般也控制在自己手裡.而且即便要考慮邊界情況,也不會這麼寫.)

最後,這個問題跟vue沒有一毛錢關係

最後的最後,下次貼代碼,不要貼張圖片,很不友好,知乎的富文本編輯器是支持粘貼代碼塊的,就像這樣:

for (let i = 0;i &< list.length; i++){ // ... }


list 的數組用vue 的語法v-for遍歷, del(id)應該傳list的下標index而不是id,直接通過this.list.splice(index,1);沒必要 這麼麻煩 還要通過js的方法找到對應的下標值。


你的理解是正確的, 第一種和第二種實現的功能點不一樣

第一種: for循環中, 找出第`id`個, 然後刪除

簡化一下就是`this.list.splice(id, 1)`

存在的問題: 一般我們不在對數組的循環中進行刪除元素的操作, 可能會導致元素的丟失, 例如:

for(let i = 0, len = this.list.length; i &< len; i++) { if(i === id) { this.list.splice(i, 1) } } // 這串代碼會導致刪除一個元素後, 數組長度縮小, 最後一次取值為undefined, 且跳過了刪除的後一個元素

第二種: 使用了函數式編程`some`, 遍歷中刪除元素`id`屬性為`${id}`的元素

這裡使用了`some`+`return true`, 為的是確保只刪除一個元素, 且函數的返回值表示是否刪除了元素

這裡的替代方法有很多種了

// 1. for循環
let delFlag = false
for(let i = this.list.length; i--;) {
if(this.list[i].id === id) {
this.list.splice(i, 1)
delFlag = true
break
}
}

// 2. 要篩選出元素, 最方便的還是filter(此時可能會刪除多個)
this.list = this.list.filter(v =&> v.id === id)

// 3. some, 確保找到第一個符合條件的就終止
this.list.some((v, i) =&> v.id === id this.list.splice(i, 1))


上面的用遍歷的索引值與傳入的id進行比較

下面的用元素的id與傳入的id進行比較

所以這兩段代碼的邏輯是不一樣的

如果元素有5個,遍歷的索引始終是0 1 2 3 4 但是它們的id可能是1 3 5 6 8

當你傳入的id為1或3時,上下代碼都能刪掉元素,但是如果傳入的元素是8,上面的代碼就不起作用了,因為i的值只遍歷到4,但是下面遍歷的是id可以找到8這個值


啥年代的代碼?Array. findIndex()它不香?


map 才是正解


2中寫法都有問題,應該在循環外刪除數據


如果是我我會這樣做

1、const idx =this.list.findIndex(e=&>e.Id===Id)//找出與傳入id相同的下標 if(idx!==-1) this.list.splice(idx,1)

2、this.list=this.list.filter(e=&>e.Id!==Id)//直接過濾與傳入的id不相同的list


這個應該是你js基礎不太好,和vue沒啥關係,第一個刪除的是下標為id的元素,第二個是刪除元素的id為id的元素,而且直接循環刪除數組自身的元素不太好,可以直接用filter感覺會好點


如果del函數接收的id就是數組下標的話,

this.list.splice(id,1)和第一種寫法是一樣的效果,

但是你既然說了第一種寫法有bug,第二種沒問題,那我就姑且認為del函數接收的id並不是數組下標,

其實從語義化來講,兩種寫法也都是有些問題的,

一般情況下不會在循環里操作原數組,

some是用來判斷數組中是否有滿足條件項的,

根據你實現的功能來看我覺得這樣寫更合適一些:

// 這種寫法會將數組裡所有id等於傳入id的項過濾掉
function del(id) {
this.list = this.list.filter(item =&> item.id !== id);
}

// 這種寫法和題目中的第二種寫法效果一致
function del(id) {
const index = this.list.findIndex(item =&> item.id === id);
this.list = [
...this.list.slice(0, index),
...this.list.slice(index + 1)
]
}


你應該傳入i 而不是id


什麼意思,那兩種


建議先findIndex 再splice


首先 del 函數傳入的 id 是指什麼?是 list 中元素的屬性,還是直接對應 list 的索引?

如果是說 id 是 list 中元素的屬性,那第一個循環明顯不對,因為是把索引和 id 比較了。

至於提問描述里說的直接 splice id 也是以 id 對應索引為前提的。


推薦閱讀:
相关文章