前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JavaScript如何优雅地告别Cannot read properties of undefined,Optional类体验

JavaScript如何优雅地告别Cannot read properties of undefined,Optional类体验

原创
作者头像
萌萌哒将军
发布2024-05-11 15:11:11
7970
发布2024-05-11 15:11:11

❝ 文章同步在公众号:萌萌哒草头将军,欢迎关注! ❞

相信很多开发者在开发中经常遇到的一个报错:

Uncaught TypeError: Cannot read properties of undefined

作为一名熟练的前端攻城狮,你一眼就能这是由于读取一个对象属性时,对象为 undefined 时导致的。

要想避免,我们需要做下判断。

代码语言:javascript
复制
let a = fetch(url, params);
a?.result?.map(console.log);

或者你使用 try catch 结构来捕获异常。

代码语言:javascript
复制
try {
  let a = fetch(url, params);
  a.result.map(console.log);
} catch (err) {
  console.log(err);
}

当然,我们还有很多其他的选择,这里就不一一列举了

接下来我介绍一种我最新学到的方案——Java 的 Optional 类。

Optional 类是 Java 中解决空指针异常(NullPointerException)的一种方案。(它和 Cannot read properties of undefined 是一样的错误),我们看看没有 Optional 类的情况

代码语言:javascript
复制
String str = null;
// System.out.println(appendTest.toString());
// 上面会触发:NullPointerException,下面是常见的应对方法
if (str !== null) {
    System.out.println(str.toString());
} else {
    System.out.println("str is null!!!");
}

但是使用 Optional 就优雅的多了

代码语言:javascript
复制
String str = null;
// 生成Optional类,ofNullablebiao 生成可以为null的对象
Optional<String> optional = Optional.ofNullable(name);

❝ 生成 Optional 类还有 of 方法,不同的是不能为 null,否则调用 ifPresent 依然会报错 NullPointerException ❞

ifPresent: 如果存在就打印它,否则不进行任何操作

代码语言:javascript
复制
optional.ifPresent(str -> System.out.println(str));
// 等价于
optional.ifPresent(System.out::println);

orElseGet:如果存在就返回它,否则执行后面的表达式

代码语言:javascript
复制
optional.orElseGet(() -> System.out.println("str is null!!"));

除此之外还有很多有意思的接口,比如我们熟悉的:map、flatmap、filter 等,

需要注意的是,因为 Optional 是一个容器类,它的方法返回的仍然是 Optional 对象,所以你可以继续对返回的 Optional 对象进行链式调用。例如:

代码语言:javascript
复制
import java.util.Optional;

public class Person {
    // something
}

public class Main {
    public static void main(String[] args) {
        // 创建一个可能为 null 的 Person 对象
        Person person = new Person("John Doe", 30);

        // 使用 Optional 对象进行链式调用
        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)));

        // 输出结果
        optionalPerson.ifPresent(p -> System.out.println("Name: " + p.getName() + ", Age: " + p.getAge()));
    }
}

更多信息可以看下面这张截图

❝ 这些方法像极了 javascript 的数组方法,但是他们的区别是,在 Java 中,Optional 类主要用于包装单个对象,以表示一个可能存在或可能不存在的值。它并不直接支持包装数组。 ❞

让我们回到 javascript,这种方案似乎可以很好的解决前端的问题。好奇的搜索 GitHub,这种方案有很多 javascript 版本的实现。

例如:https://github.com/JasonStorey/Optional.js

代码语言:javascript
复制
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);

这看起来妙极了!!!

那么这种方案是怎么实现的呢?关键是函数返回值依然是个 Optional 对象。下面我们简单的实现一下这个过程.

代码语言:javascript
复制
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

你觉得这个方案可以吗?相信大家读到这里心中已经有答案了吧

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档