You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Angular服务map转换哈利波特API数据时年龄字段出现NaN的原因排查

问题:处理哈利波特API数据时,部分角色的age字段返回NaN

我正在调用一个返回哈利波特角色数据的API,接口返回的数据示例如下:

{"name": "Harry Potter", "species": "human", "gender": "male", "dateOfBirth": "31-07-1980", "yearOfBirth": 1980, "eyeColour": "green", "hairColour": "black", "wand": { "wood": "holly", "core": "phoenix feather" }, "patronus": "stag", "hogwartsStudent": true, "hogwartsStaff": false, "actor": "Daniel Radcliffe", "alive": true, "image": "http://hp-api.herokuapp.com/images/harry.jpg"}

我希望展示角色列表,仅显示namepatronusageimage这几个属性,为此做了以下实现:

  1. TypeScript接口定义:
export interface Character {
  name: string;
  patronus: string;
  dateOfBirth: string;
  image: string;
  age: number;
}
  1. 服务中的方法实现:
getStudents() {
  return this.http.get<Character[]>(this.baseUrl + 'students').pipe(
    map( response => response.map( respItem => (
      {
        name: respItem.name,
        patronus: respItem.patronus,
        dateOfBirth: respItem.dateOfBirth,
        image: respItem.image,
        age: new Date().getFullYear() - new Date(respItem.dateOfBirth).getFullYear()
      }
    ) ) )
  );
}

(注:我知道还需要处理生日是否已过的逻辑,但这不是当前问题的重点)

  1. 组件代码:
@Component({
  selector: 'app-students',
  templateUrl: './students.component.html',
  styleUrls: ['./students.component.css']
})
export class StudentsComponent implements OnInit {
  students: Character[]= [];
  constructor(private hogwartsService: HogwartsService) { }
  ngOnInit(): void {
    this.getStudents();
  }
  getStudents(){
    this.hogwartsService.getStudents().subscribe(response => {
      this.students = response;
      console.log(this.students);
    });
  }
}

现在的问题是:部分角色的age字段能正常显示为数字,但另一部分却返回NaN,请问这是什么原因?


回答

这个问题的核心原因是API返回的某些角色数据中没有dateOfBirth字段,或者该字段的值是空字符串/无效的日期格式,导致new Date(respItem.dateOfBirth)创建出一个无效的Date对象,调用它的getFullYear()方法时会返回NaN,最终计算new Date().getFullYear() - NaN的结果自然也是NaN

举个实际场景的例子:如果某个角色的dateOfBirthundefined或者空字符串,执行new Date(undefined)会得到一个Invalid Date对象,再调用getFullYear()就会返回NaN,最终年龄计算结果就是NaN

要解决这个问题,你需要在计算age之前先检查dateOfBirth的有效性,调整后的服务方法可以这样写:

getStudents() {
  return this.http.get<any[]>(this.baseUrl + 'students').pipe(
    map(response => response.map(respItem => {
      let age: number | null = null;
      // 先检查dateOfBirth是否存在,再验证日期格式是否有效
      if (respItem.dateOfBirth) {
        const birthDate = new Date(respItem.dateOfBirth);
        // 通过getTime()判断日期是否有效(无效日期的getTime()返回NaN)
        if (!isNaN(birthDate.getTime())) {
          age = new Date().getFullYear() - birthDate.getFullYear();
          // (可选)这里可以补充生日是否已过的逻辑,让年龄计算更准确
        }
      }
      return {
        name: respItem.name,
        patronus: respItem.patronus,
        dateOfBirth: respItem.dateOfBirth,
        image: respItem.image,
        age: age
      };
    }))
  );
}

另外,你的Character接口里定义dateOfBirth为必填的string,但实际API可能返回部分角色没有这个字段,建议把它改成可选类型,同时调整age的类型允许null

export interface Character {
  name: string;
  patronus: string;
  dateOfBirth?: string; // 改为可选字段
  image: string;
  age?: number | null; // 允许age为null或未定义
}

这样处理后,那些没有有效出生日期的角色的age会被设为null(你也可以根据需求改成默认值比如0),就不会出现NaN的情况了。

内容的提问来源于stack exchange,提问作者armando t

火山引擎 最新活动