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

Using Nested JavaScript Functions in Refactoring: Improving the Design of Existing Code (2nd Edition)

Finally decided to use nested functions, and it still runs normally

1. While studying Refactoring: Improving the Design of Existing Code (2nd Edition), I noticed that the statement function was missing a closing } at the end, which caused an issue with the code formatting display. See Figure 1.

While studying Refactoring: Improving the Design of Existing Code (2nd Edition), I noticed that the statement function was missing a closing } at the end, which caused an issue with the code formatting display
Figure 1
JavaScript

    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) {
            let thisAmount = amountFor(perf
                , playFor(perf)
            );

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

            // print line for this order
            result += ` ${playFor(perf).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;

2. I kept assuming that the } was simply omitted from the original code, so I had to add it myself. The final program implementation is as follows.

JavaScript


    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 playFor(aPerformance) {
        return plays[aPerformance.playID];
    }

    function amountFor(aPerformance) {
        let result = 0;
        switch (playFor(aPerformance).type) {
            case "tragedy":
                result = 40000;
                if (aPerformance.audience > 30) {
                    result += 1000 * (aPerformance.audience - 30);
                }
                break;
            case "comedy":
                result = 30000;
                if (aPerformance.audience > 20) {
                    result += 10000 + 500 * (aPerformance.audience - 20);
                }
                result += 300 * aPerformance.audience;
                break;
            default:
                throw new Error(`unknown type: ${playFor(aPerformance).type}`);
        }
        return result;
    }

    function volumeCreditsFor(aPerformance) {
        let result = 0;
        result += Math.max(aPerformance.audience - 30, 0);
        if ("comedy" === playFor(aPerformance).type) result += Math.floor(aPerformance.audience / 5);
        return result;
    }

    function usd(aNumber) {
        return new Intl.NumberFormat("en-US",
            {
                style: "currency", currency: "USD",
                minimumFractionDigits: 2
            }).format(aNumber / 100);
    }

    function totalVolumeCredits() {
        let result = 0;
        for (let perf of invoice.performances) {
            result += volumeCreditsFor(perf);
        }
        return result;
    }

    function totalAmount() {
        let result = 0;
        for (let perf of invoice.performances) {
            result += amountFor(perf);
        }
        return result;
    }

    function statement(invoice, plays) {
        let result = `Statement for ${invoice.customer}\n`;
        for (let perf of invoice.performances) {
            result += ` ${playFor(perf).name}: ${usd(amountFor(perf))} (${perf.audience} seats)\n`;
        }
        result += `Amount owed is ${usd(totalAmount())}\n`;
        result += `You earned ${totalVolumeCredits()} credits\n`;
        return result;
    }

    console.log(statement(invoice, plays));


3. In section 1.5 Progress: A Lot of Nested Functions — “Refactored to this point, it is time to stop and admire the full view of the code.” I discovered that the closing } of the statement function actually exists. However, because it contains some nested functions and the full view was not displayed, it was not visible. See Figure 2.

In section 1.5 Progress: A Lot of Nested Functions — "Refactored to this point, it is time to stop and admire the full view of the code." I discovered that the closing } of the statement function actually exists. However, because it contains some nested functions and the full view was not displayed, it was not visible
Figure 2

4. I finally decided to use nested functions, and the program still runs normally. See Figure 3.

Finally decided to use nested functions, and it still runs normally
Figure 3
JavaScript


    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 result = `Statement for ${invoice.customer}\n`;
        for (let perf of invoice.performances) {
            result += ` ${playFor(perf).name}: ${usd(amountFor(perf))} (${perf.audience} seats)\n`;
        }
        result += `Amount owed is ${usd(totalAmount())}\n`;
        result += `You earned ${totalVolumeCredits()} credits\n`;
        return result;

        function totalAmount() {
            let result = 0;
            for (let perf of invoice.performances) {
                result += amountFor(perf);
            }
            return result;
        }

        function totalVolumeCredits() {
            let result = 0;
            for (let perf of invoice.performances) {
                result += volumeCreditsFor(perf);
            }
            return result;
        }

        function usd(aNumber) {
            return new Intl.NumberFormat("en-US",
                {
                    style: "currency", currency: "USD",
                    minimumFractionDigits: 2
                }).format(aNumber / 100);
        }

        function volumeCreditsFor(aPerformance) {
            let result = 0;
            result += Math.max(aPerformance.audience - 30, 0);
            if ("comedy" === playFor(aPerformance).type) result += Math.floor(aPerformance.audience / 5);
            return result;
        }

        function playFor(aPerformance) {
            return plays[aPerformance.playID];
        }

        function amountFor(aPerformance) {
            let result = 0;
            switch (playFor(aPerformance).type) {
                case "tragedy":
                    result = 40000;
                    if (aPerformance.audience > 30) {
                        result += 1000 * (aPerformance.audience - 30);
                    }
                    break;
                case "comedy":
                    result = 30000;
                    if (aPerformance.audience > 20) {
                        result += 10000 + 500 * (aPerformance.audience - 20);
                    }
                    result += 300 * aPerformance.audience;
                    break;
                default:
                    throw new Error(`unknown type: ${playFor(aPerformance).type}`);
            }
            return result;
        }
    }

    console.log(statement(invoice, plays));


关于作者 · 持续学习与技术实践

我是一名拥有 15 年以上开发经验的技术从业者,自 2013 年起持续运营个人技术博客,记录工作与个人项目中遇到的真实问题,以及解决问题过程中的探索、实践和思考。

除了技术写作,我也在持续开发和维护自己的独立项目,探索新技术和新工具在实际场景中的应用。我始终相信,没有不值得去解决的问题,也没有不值得去学习的技术。

如果这篇文章对你有所帮助,欢迎浏览博客中的其他文章,也欢迎交流技术经验与想法。

关于我  ·  GitHub  ·  邮件联系