You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Angular 12+中转换使用带window.prototype的JavaScript函数

AngularJS迁移至Angular 12+:JSONLoop构造函数的改造与使用方案

问题背景

从AngularJS迁移到Angular 12+时,原项目中挂载在window对象上的JSONLoop构造函数(含原型方法)无法直接在Angular组件中使用,需要进行适配改造。以下是原代码、旧使用方式及示例数据:

原JavaScript代码

(function(window) {
  var nodes = [];
  window.JSONLoop = function(obj, idPropertyName, childrenPropertyName) {
    this.id = idPropertyName;
    this.children = childrenPropertyName;
    this.count = 0;
    this.countNodes(obj);
    this.total = this.count + 0;
  }

  window.JSONLoop.prototype = {
    constructor: JSONLoop,
    isEmpty: function(obj) {
      for(var property in obj) {
        return false;
      }
      return true;
    },
    countNodes: function(obj) {
      var that = this;
      this.count++;
      return (function() {
        if (!obj || that.isEmpty(obj)) {
          return false;
        } else {
          if (obj[that.children]) {
            obj[that.children].forEach(function(child) {
              that.countNodes(child);
            });
          }
        }
      })();
    },
    findNodeById: function(obj, id, callback) {
      if (obj[this.id] === id) {
        this.count = this.total + 0;
        callback(null, obj);
      } else {
        if (this.count === 1) {
          this.count = this.total + 0;
          callback('the node does not exist', null);
        }
        this.count--;
        if (obj[this.children]) {
          var that = this;
          obj[this.children].forEach(function(node) {
            that.findNodeById(node, id, callback);
          });
        }
      }
    }
  };
}(window));

AngularJS中的使用方式

var jsonloop = new JSONLoop(data[0],'id', 'childBeans');
jsonloop.findNodeById(data[0], dataId.substr(2), function(err, node) {
  if (err) {
    childItemObj = "";
  } else {
    childItemObj = node;
  }
});

示例JSON数据

{
  "hierarchy": "3",
  "hierarchyStr": "product",
  "id": "1730637",
  "levelId": null,
  "parentId": "0",
  "smartBeans": [
    {
      "hierarchy": "3.3",
      "hierarchyStr": "product~@product-1",
      "id": "1730637-1730638"
    },
    {
      "hierarchy": "3.4",
      "hierarchyStr": "product~@product-2",
      "id": "1730637-1730670"
    },
    {
      "hierarchy": "3.5",
      "hierarchyStr": "product~@product-3",
      "id": "1730637-1730686"
    },
    {
      "hierarchy": "3.6",
      "hierarchyStr": "product~@product-4",
      "id": "1730637-1730696"
    }
  ]
}

解决方案

1. 将JSONLoop转换为TypeScript类

把原构造函数和原型方法改写成ES6类,适配Angular的TypeScript环境,同时优化this指向问题:

export class JSONLoop<T> {
  private idProp: string;
  private childrenProp: string;
  public count: number;
  public total: number;

  constructor(obj: T, idPropertyName: string, childrenPropertyName: string) {
    this.idProp = idPropertyName;
    this.childrenProp = childrenPropertyName;
    this.count = 0;
    this.countNodes(obj);
    this.total = this.count;
  }

  private isEmpty(obj: any): boolean {
    for (const property in obj) {
      return false;
    }
    return true;
  }

  private countNodes(obj: T): void {
    this.count++;
    if (!obj || this.isEmpty(obj)) {
      return;
    }
    const children = (obj as any)[this.childrenProp];
    if (children && Array.isArray(children)) {
      children.forEach(child => this.countNodes(child));
    }
  }

  // 保留原回调风格方法
  findNodeById(obj: T, id: string, callback: (err: string | null, node: T | null) => void): void {
    if ((obj as any)[this.idProp] === id) {
      this.count = this.total;
      callback(null, obj);
      return;
    }
    if (this.count === 1) {
      this.count = this.total;
      callback('the node does not exist', null);
      return;
    }
    this.count--;
    const children = (obj as any)[this.childrenProp];
    if (children && Array.isArray(children)) {
      children.forEach(node => this.findNodeById(node, id, callback));
    }
  }

  // 新增Promise风格方法,更适配Angular异步场景
  async findNodeByIdAsync(obj: T, id: string): Promise<T> {
    return new Promise((resolve, reject) => {
      this.findNodeById(obj, id, (err, node) => {
        if (err) {
          reject(new Error(err));
        } else if (node) {
          resolve(node);
        } else {
          reject(new Error('Node not found'));
        }
      });
    });
  }
}

2. 在Angular组件中使用

在组件中导入JSONLoop类,然后像原方式一样创建实例并调用方法:

import { Component, OnInit } from '@angular/core';
import { JSONLoop } from './json-loop'; // 根据实际文件路径调整

@Component({
  selector: 'app-your-component',
  templateUrl: './your-component.component.html',
  styleUrls: ['./your-component.component.css']
})
export class YourComponent implements OnInit {
  childItemObj: any;

  ngOnInit(): void {
    // 假设data是从接口或其他地方获取的树形数据
    const data = [/* 你的树形数据 */];
    const dataId = 'xx1730637'; // 示例ID

    // 回调风格使用
    const jsonloop = new JSONLoop(data[0], 'id', 'smartBeans'); // 注意这里children属性是smartBeans,和示例JSON对应
    jsonloop.findNodeById(data[0], dataId.substr(2), (err, node) => {
      if (err) {
        this.childItemObj = '';
      } else {
        this.childItemObj = node;
      }
    });

    // Promise风格使用(推荐)
    jsonloop.findNodeByIdAsync(data[0], dataId.substr(2))
      .then(node => this.childItemObj = node)
      .catch(() => this.childItemObj = '');
  }
}

3. 注意事项

  • 确保传入的childrenPropertyName和你的JSON数据中的子节点数组键名一致(示例中是smartBeans,原AngularJS代码中是childBeans,根据实际数据调整)
  • TypeScript泛型T可以替换为你定义的树形节点接口,增强类型安全
  • 原代码中count和total的逻辑可以根据需求验证是否需要保留,若仅需查找节点功能,可简化相关计数逻辑

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 07:35:24