为何两段toggleComplete函数代码执行结果不同?一段丢失数组元素
两段toggleComplete代码执行结果差异的原因解析
问题描述
为何以下第一段toggleComplete函数代码执行后,todos数组仅保留completed相关元素、其余元素被删除?而第二段代码执行后,数组所有元素保留,仅修改目标元素的completed属性(符合预期行为)。
第一段代码
const toggleComplete = (id) => { const updatedTodos = todos.map((todo) => todo.id === id ? todo.completed = !todo.completed : todo ); setTodos(updatedTodos); }
第二段代码
const toggleComplete = (id) => { const updatedTodos = todos.map((todo) => { if (todo.id === id) { todo.completed = !todo.completed; } return todo; }); setTodos(updatedTodos); }
差异原因解析
核心差异在于map回调函数的返回值逻辑不同:
- 第一段代码使用三元表达式时,匹配id的分支执行的是
todo.completed = !todo.completed——这是一个赋值操作,赋值语句的返回值是被赋的布尔值(true/false),而非修改后的整个todo对象。因此map遍历后,updatedTodos数组中,匹配id的位置会被替换成布尔值,不匹配的位置保留原todo对象。后续渲染或处理时,布尔值没有todo对象的属性(如id、text等),会被过滤或忽略,看起来就像“其余元素被删除”。 - 第二段代码的if语句仅修改todo对象的completed属性,无论是否匹配id,最终都会返回整个todo对象。因此map生成的updatedTodos数组全是完整的todo对象,所有元素都被保留,仅目标元素的completed属性被修改,符合预期。
补充:符合React不可变原则的写法
两段代码都直接修改了原todo对象(对象是引用类型),虽然能实现功能,但违反了React的不可变数据原则,可能导致意外的渲染问题。推荐创建新对象来修改属性:
const toggleComplete = (id) => { const updatedTodos = todos.map((todo) => todo.id === id ? {...todo, completed: !todo.completed} : todo ); setTodos(updatedTodos); };
内容的提问来源于stack exchange,提问作者metrallador10
相关产品推荐
相关产品推荐

