没有不值得去解决的问题,也没有不值得去学习的技术!

重构 改善既有代码的设计 ( 第 2 版 ),第一个示例的实际运行,报错:Uncaught TypeError: invoice.performances is not iterable

运行时,报错:Uncaught TypeError: invoice.performances is not iterable
1、该剧团将剧目的数据存储在一个简单的JSON文件中。


{
  "hamlet": {"name": "Hamlet", "type": "tragedy"},
  "as-like": {"name": "As You Like It", "type": "comedy"},
  "othello": {"name": "Othello", "type": "tragedy"}
}


2、他们开出的账单也存储在一个JSON文件里。


[
  {
    "customer": "BigCo",
    "performances": [
      {
        "playID": "hamlet",
        "audience": 55
      },
      {
        "playID": "as-like",
        "audience": 35
      },
      {
        "playID": "othello",
        "audience": 40
      }
    ]
  }
]


3、下面这个简单的函数用于打印账单详情。


function statement(invoice, plays) {
	let totalAmount = 0;
	let volumeCredits = 0;
	let result = `Statement for ${invoice.customer}\n`;
	const format = new Intl.NumberFormat("en-US",
		{
			style: "currency", currency: "USD",
			minimumFractionDigits: 2
		}).format;
	for (let perf of invoice.performances) {
		const play = plays[perf.playID];
		let thisAmount = 0;

		switch (play.type) {
			case "tragedy":
				thisAmount = 40000;
				if (perf.audience > 30) {
					thisAmount += 1000 * (perf.audience - 30);
				}
				break;
			case "comedy":
				thisAmount = 30000;
				if (perf.audience > 20) {
					thisAmount += 10000 + 500 * (perf.audience - 20);
				}
				thisAmount += 300 * perf.audience;
				break;
			default:
				throw new Error(`unknown type: ${play.type}`);
		}

		// add volume credits
		volumeCredits += Math.max(perf.audience - 30, 0);
		// add extra credit for every ten comedy attendees
		if ("comedy" === play.type) volumeCredits += Math.floor(perf.audience / 5);

		// print line for this order
		result += ` ${play.name}: ${format(thisAmount / 100)} (${perf.audience} seats)\n`;
		totalAmount += thisAmount;
	}
	result += `Amount owed is ${format(totalAmount / 100)}\n`;
	result += `You earned ${volumeCredits} credits\n`;
	return result;
}


4、用上面的数据文件(invoices.json和plays.json)作为测试输入,运行这段代码,会得到如下输出:


Statement for BigCo
  Hamlet: $650.00 (55 seats)
  As You Like It: $580.00 (35 seats)
  Othello: $500.00 (40 seats)
Amount owed is $1,730.00
You earned 47 credits


5、决定将数据文件的数据放入变量中,然后将运行结果通过浏览器控制台打印输出。新建 html 文件:statement.html
<pre class="wp-block-syntaxhighlighter-code">

<script>
    let invoice = [
        {
            "customer": "BigCo",
            "performances": [
                {
                    "playID": "hamlet",
                    "audience": 55
                },
                {
                    "playID": "as-like",
                    "audience": 35
                },
                {
                    "playID": "othello",
                    "audience": 40
                }
            ]
        }
    ];

    let plays = {
        "hamlet": {"name": "Hamlet", "type": "tragedy"},
        "as-like": {"name": "As You Like It", "type": "comedy"},
        "othello": {"name": "Othello", "type": "tragedy"}
    };

    function statement(invoice, plays) {
        let totalAmount = 0;
        let volumeCredits = 0;
        let result = `Statement for ${invoice.customer}\n`;
        const format = new Intl.NumberFormat("en-US",
            {
                style: "currency", currency: "USD",
                minimumFractionDigits: 2
            }).format;
        for (let perf of invoice.performances) {
            const play = plays[perf.playID];
            let thisAmount = 0;

            switch (play.type) {
                case "tragedy":
                    thisAmount = 40000;
                    if (perf.audience > 30) {
                        thisAmount += 1000 * (perf.audience - 30);
                    }
                    break;
                case "comedy":
                    thisAmount = 30000;
                    if (perf.audience > 20) {
                        thisAmount += 10000 + 500 * (perf.audience - 20);
                    }
                    thisAmount += 300 * perf.audience;
                    break;
                default:
                    throw new Error(`unknown type: ${play.type}`);
            }

            // add volume credits
            volumeCredits += Math.max(perf.audience - 30, 0);
            // add extra credit for every ten comedy attendees
            if ("comedy" === play.type) volumeCredits += Math.floor(perf.audience / 5);

            // print line for this order
            result += ` ${play.name}: ${format(thisAmount / 100)} (${perf.audience} seats)\n`;
            totalAmount += thisAmount;
        }
        result += `Amount owed is ${format(totalAmount / 100)}\n`;
        result += `You earned ${volumeCredits} credits\n`;
        return result;
    }

    console.log(statement(invoice, plays));
</script>

</pre>
6、运行时,报错:Uncaught TypeError: invoice.performances is not iterable。如图1
运行时,报错:Uncaught TypeError: invoice.performances is not iterable
图1


Uncaught TypeError: invoice.performances is not iterable
    at statement (statement.html:35:28)
    at statement.html:71:13
statement @ statement.html:35
(匿名) @ statement.html:71


7、原因在于 invoice 并非一个对象,而是一个数组。将 invoice 的定义的 [] 去掉。如图2
原因在于 invoice 并非一个对象,而是一个数组。将 invoice 的定义的 [] 去掉
图2
<pre class="wp-block-syntaxhighlighter-code">

<script>
    let invoice = {
        "customer": "BigCo",
        "performances": [
            {
                "playID": "hamlet",
                "audience": 55
            },
            {
                "playID": "as-like",
                "audience": 35
            },
            {
                "playID": "othello",
                "audience": 40
            }
        ]
    };

    let plays = {
        "hamlet": {
            "name": "Hamlet",
            "type": "tragedy"
        },
        "as-like": {
            "name": "As You Like It",
            "type": "comedy"
        },
        "othello": {
            "name": "Othello",
            "type": "tragedy"
        }
    };

    function statement(invoice, plays) {
        let totalAmount = 0;
        let volumeCredits = 0;
        let result = `Statement for ${invoice.customer}\n`;
        const format = new Intl.NumberFormat("en-US",
            {
                style: "currency", currency: "USD",
                minimumFractionDigits: 2
            }).format;
        for (let perf of invoice.performances) {
            const play = plays[perf.playID];
            let thisAmount = 0;

            switch (play.type) {
                case "tragedy":
                    thisAmount = 40000;
                    if (perf.audience > 30) {
                        thisAmount += 1000 * (perf.audience - 30);
                    }
                    break;
                case "comedy":
                    thisAmount = 30000;
                    if (perf.audience > 20) {
                        thisAmount += 10000 + 500 * (perf.audience - 20);
                    }
                    thisAmount += 300 * perf.audience;
                    break;
                default:
                    throw new Error(`unknown type: ${play.type}`);
            }

            // add volume credits
            volumeCredits += Math.max(perf.audience - 30, 0);
            // add extra credit for every ten comedy attendees
            if ("comedy" === play.type) volumeCredits += Math.floor(perf.audience / 5);

            // print line for this order
            result += ` ${play.name}: ${format(thisAmount / 100)} (${perf.audience} seats)\n`;
            totalAmount += thisAmount;
        }
        result += `Amount owed is ${format(totalAmount / 100)}\n`;
        result += `You earned ${volumeCredits} credits\n`;
        return result;
    }

    console.log(statement(invoice, plays));
</script>

</pre>
8、输出符合预期,不再报错。如图3
输出符合预期,不再报错
图3


Statement for BigCo
 Hamlet: $650.00 (55 seats)
 As You Like It: $580.00 (35 seats)
 Othello: $500.00 (40 seats)
Amount owed is $1,730.00
You earned 47 credits


需要长期技术维护或远程问题排查?

我是拥有 15+ 年经验的 PHP / Go 后端工程师,长期关注已有系统维护、Bug 修复、性能优化、服务器排查、WordPress 网站维护和小功能迭代。

如果你的项目遇到以下情况,可以先从一次小问题排查开始合作:

  • ✅ PHP / Laravel / Yii2 老项目无人维护
  • ✅ Go / Gin 后端接口需要排查或优化
  • ✅ WordPress 网站访问慢、报错或插件冲突
  • ✅ Nginx / MySQL / Redis / Linux 服务器异常
  • ✅ CDN / Cloudflare / DNS / HTTPS 配置问题
  • ✅ 需要长期远程技术支持或兼职维护

更多介绍请查看:关于我 & 合作

微信:13980074657
邮箱:shuijingwanwq@gmail.com
Telegram:@shuijingwan
GitHub:https://github.com/shuijingwan

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理