6.2 场景2
来看看下面这个例子:
function test(fruit, quantity) { const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries']; // 条件1: fruit 必须非空 if (fruit) { // 条件2: 必须是红色的水果 if (redFruits.includes(fruit)) { console.log('red'); // 条件3: 必须大于10个 if (quantity > 10) { console.log('big quantity'); } } } else { throw new Error('No fruit!'); } } test(null); // error: No fruits test('apple'); // red test('apple', 20); // red, big quantity
看看上面的代码,我们有:
- 1个if/else语句,过滤掉无效的条件
- 3层嵌套的if语句(条件1、2和3)。
我个人遵循的一般规则是在将一些比较容易处理、计算量小、小概率的提前返回。
function test(fruit, quantity) { const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries']; // 先判断小概率情况,提前返回 if (!fruit) throw new Error('No fruit!'); if (redFruits.includes(fruit)) { console.log('red'); if (quantity > 10) { console.log('big quantity'); } } }
通过这样做,我们就少了一层嵌套语句。这种编码方式很好,特别是当你有很长的if语句时(想象一下,你需要滚动到最下面才知道有一个else语句,这可读性可能不会太好)。我们可以进一步减少嵌套的if,通过倒置条件和提前返回。比如:
function test(fruit, quantity) { const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries']; if (!fruit) throw new Error('No fruit!'); if (!redFruits.includes(fruit)) return; console.log('red'); if (quantity > 10) { console.log('big quantity'); } }
通过颠倒条件2的条件,我们的代码现在已经没有了嵌套的语句,代码变得很简洁直观。
7、隐藏高阶技能:find(Boolean)
写 react 的同学可能在一些组件复用的场景会经常遇到这种情况:组件中有少部分组件会根据传入的props属性不同进行展示。
function ComponentByType({ type }) { if (type === "type_1") { return ( <> {/* 其他很复杂的组件 */} <Component1 /> {/* 其他很复杂的组件 */} </> ); } if (type === "type_2") { return ( <> {/* 其他很复杂的组件 */} <Component2 /> {/* 其他很复杂的组件 */} </> ); } if (type === "type_3") { return ( <> {/* 其他很复杂的组件 */} <Component3 /> {/* 其他很复杂的组件 */} </> ); } if (type === "type_4") { return ( <> {/* 其他很复杂的组件 */} <Component4 /> {/* 其他很复杂的组件 */} </> ); } }
而这种情况,可以通过find(Boolean)
这个小技巧来获得极大的简化:
function ComponentByType({ type }) { return ( <> {/* 其他很复杂的组件 */} <> { [ type === "type_1" && <Component1 />, type === "type_2" && <Component2 />, type === "type_3" && <Component3 />, type === "type_4" && <Component4 /> ].find(Boolean) } </> {/* 其他很复杂的组件 */} </> ); }
find(Boolean)
可以实现条件判断,因为在JavaScript中,布尔值的true和false可以被转换为数字1和0。在这个例子里,当某个条件不满足时,对应的React组件(例如<Component1 />
)会被解析为布尔值false并存储在数组中,相反当条件满足时,对应的React组件会被解析为一个真值true。这样,使用find(Boolean)
就可以找到第一个真值(即第一个满足条件的React组件),并把它渲染到页面上。
需要注意的是,当没有任何一个条件满足时,
.find()
方法返回的是undefined,会导致React渲染错误。但由于在这个例子中我们把结果用短路语法忽略了,因此不会有报错。
如果希望更准确地处理没有满足条件的情况,可以显式地在.find()
后面添加一个默认返回值,在找不到满足条件的组件时返回默认组件。例如:
[ type === "type_1" && <Component1 />, type === "type_2" && <Component2 />, type === "type_3" && <Component3 />, type === "type_4" && <Component4 /> ].find(Boolean) || <DefaultComponent />
这样,当四种类型都不匹配时,就会默认渲染 <DefaultComponent>
组件,避免了React渲染错误。通过使用find(Boolean)
,可以简化代码,避免了使用多个if/else
语句或switch/case
语句的复杂性和冗长性。
原理是什么呢?
find(Boolean)
的作用是查找数组中第一个布尔值为true
的元素,并返回该元素的值。数组中包含多个条件语句以及相应的React组件,当某个条件满足时,对应的组件会被返回并渲染到页面上;否则会返回false
,由于我们使用了条件运算符&&
,所以这个返回值会被自动忽略。
比如一个简单的例子:
[0,false,null,1,2].find(Boolean) // 返回 1
在不加 new
的情况下调用 Boolean
函数会将传入的参数转换为布尔值。对于数组中的各个元素,利用 Boolean
函数进行类型转换后的结果如下:
0
被转换为false
false
本身就是布尔值false
null
被转换为false
1
被转换为true
2
被转换为true
因此,使用 find
方法查找第一个真值时,返回了第一个布尔值为 true
的元素的索引。在这个数组中,第一个布尔值为 true
的元素是 1
,它的索引是 3,因此 find
方法返回了 1。需要注意的是,如果该数组中不存在任何布尔值为 true
的元素,则 find
方法返回 undefined。
[0,false,null,1,2].map(Boolean); // [false, false, false, true, true] [0,false,null,1,2].find(Boolean); // 1
其中,map
方法将数组中的每个元素都应用一次 Boolean
函数,得到一个新的布尔类型的数组。可以看到,在这个新数组中,第一个布尔值为 true
的元素是 true
,它的索引是 3。因此,find
方法在原始数组中查找第一个布尔值为 true
的元素时,返回了 1。