JavaScript如何優(yōu)雅地告別Cannot read properties of undefined,Optional類(lèi)體驗(yàn)
相信很多開(kāi)發(fā)者在開(kāi)發(fā)中經(jīng)常遇到的一個(gè)報(bào)錯(cuò):
Uncaught TypeError: Cannot read properties of undefined.
圖片
作為一名熟練的前端攻城獅,你一眼就能這是由于讀取一個(gè)對(duì)象屬性時(shí),對(duì)象為 undefined 時(shí)導(dǎo)致的。
要想避免,我們需要做下判斷。
let a = fetch(url, params);
a?.result?.map(console.log);
或者你使用 try catch 結(jié)構(gòu)來(lái)捕獲異常。
try {
let a = fetch(url, params);
a.result.map(console.log);
} catch (err) {
console.log(err);
}
當(dāng)然,我們還有很多其他的選擇,這里就不一一列舉了。
接下來(lái)我介紹一種我最新學(xué)到的方案——Java 的 Optional 類(lèi)。
Optional 類(lèi)是 Java 中解決空指針異常(NullPointerException)的一種方案。(它和 Cannot read properties of undefined 是一樣的錯(cuò)誤),我們看看沒(méi)有 Optional 類(lèi)的情況。
String str = null;
// System.out.println(appendTest.toString());
// 上面會(huì)觸發(fā):NullPointerException,下面是常見(jiàn)的應(yīng)對(duì)方法
if (str !== null) {
System.out.println(str.toString());
} else {
System.out.println("str is null!!!");
}
但是使用 Optional 就優(yōu)雅的多了。
String str = null;
// 生成Optional類(lèi),ofNullablebiao 生成可以為null的對(duì)象
Optional<String> optional = Optional.ofNullable(name);
生成 Optional 類(lèi)還有 of 方法,不同的是不能為 null,否則調(diào)用 ifPresent 依然會(huì)報(bào)錯(cuò) NullPointerException。
ifPresent: 如果存在就打印它,否則不進(jìn)行任何操作。
optional.ifPresent(str -> System.out.println(str));
// 等價(jià)于
optional.ifPresent(System.out::println);
orElseGet:如果存在就返回它,否則執(zhí)行后面的表達(dá)式。
optional.orElseGet(() -> System.out.println("str is null!!"));
除此之外還有很多有意思的接口,比如我們熟悉的:map、flatmap、filter 等。
需要注意的是,因?yàn)?Optional 是一個(gè)容器類(lèi),它的方法返回的仍然是 Optional 對(duì)象,所以你可以繼續(xù)對(duì)返回的 Optional 對(duì)象進(jìn)行鏈?zhǔn)秸{(diào)用。例如:
import java.util.Optional;
public class Person {
// something
}
public class Main {
public static void main(String[] args) {
// 創(chuàng)建一個(gè)可能為 null 的 Person 對(duì)象
Person person = new Person("John Doe", 30);
// 使用 Optional 對(duì)象進(jìn)行鏈?zhǔn)秸{(diào)用
Optional<Person> optionalPerson = Optional.ofNullable(person)
.filter(p -> p.getAge() >= 18)
.map(p -> new Person(p.getName().toUpperCase(), p.getAge())
.flatMap(p -> Optional.of(new Person(p.getName(), p.getAge() + 1)));
// 輸出結(jié)果
optionalPerson.ifPresent(p -> System.out.println("Name: " + p.getName() + ", Age: " + p.getAge()));
}
}
更多信息可以看下面這張截圖:
圖片
這些方法像極了 javascript 的數(shù)組方法,但是他們的區(qū)別是,在 Java 中,Optional 類(lèi)主要用于包裝單個(gè)對(duì)象,以表示一個(gè)可能存在或可能不存在的值。它并不直接支持包裝數(shù)組。
讓我們回到 javascript,這種方案似乎可以很好的解決前端的問(wèn)題。好奇的搜索 GitHub,這種方案有很多 javascript 版本的實(shí)現(xiàn)。
例如:https://github.com/JasonStorey/Optional.js
const Optional = require("optional-js");
// Define some simple operations
const getUserId = (username) => (username === "root" ? 1234 : 0);
const verify = (userId) => userId === 1234;
const login = (userId) => console.log("Logging in as : " + userId);
// Declare a potentially undefined value
const username = process.argv[2];
// Wrap username in an Optional, and build a pipeline using our operations
Optional.ofNullable(username).map(getUserId).filter(verify).ifPresent(login);
這看起來(lái)妙極了!!!
那么這種方案是怎么實(shí)現(xiàn)的呢?關(guān)鍵是函數(shù)返回值依然是個(gè) Optional 對(duì)象。下面我們簡(jiǎn)單的實(shí)現(xiàn)一下這個(gè)過(guò)程。
class Optional {
constructor(value) {
this.value = value;
}
static of(value) {
return new Optional(value);
}
isPresent() {
return this.value !== undefined && this.value !== null;
}
map(mapper) {
if (this.isPresent()) {
const mappedValue = mapper(this.value);
return Optional.of(mappedValue);
}
return Optional.ofNullable(null);
}
flatMap(mapper) {
if (this.isPresent()) {
const mappedValue = mapper(this.value);
if (mappedValue instanceof Optional) {
return mappedValue;
}
return Optional.ofNullable(mappedValue);
}
return Optional.ofNullable(null);
}
orElse(defaultValue) {
return this.isPresent() ? this.value : defaultValue;
}
static ofNullable(value) {
return Optional.of(value);
}
}
function getNameLength(person) {
return Optional.ofNullable(person)
.map((p) => p.name)
.map((name) => name.length)
.orElse(0);
}
const person = { name: "John Doe" };
console.log(getNameLength(person)); // 輸出:8
const emptyPerson = null;
console.log(getNameLength(emptyPerson)); // 輸出:0
你覺(jué)得這個(gè)方案可以嗎?相信大家讀到這里心中已經(jīng)有答案了吧?