Google脚本-在另一个函数中调用函数时出错

时间:2020-02-17 02:15:06

标签: javascript google-apps-script

我要发布下面的全部代码。

我正在使用Google脚本,从不断变化的工作表中提取一些数据,执行计算,然后重新填充工作表。

正在将数据调用到应用程序中,因此我正在尝试尽快进行计算(因此,如果有人可以告诉我更有效的方法来执行此操作,这也将有所帮助)。

当我尝试调用conda函数或invoicePrice()函数时,我收到TypeError:函数找不到。

tiers()

1 个答案:

答案 0 :(得分:2)

问题

从另一个函数(invoicePrice调用时,正确声明的函数(calcsOnColumns2)是undefined

复制步骤

想象一下,您有三个名为ABC的函数,然后调用B会导致错误:

function A() {
  var A = 0;
  return [A];
}

function C() {
  var a = A();
  var A = a[0];
}

function B() {
  A();
  C();
}

您可能已经注意到这是您的功能归根结底-行为是由于起重

  1. 函数B调用A,该函数返回第一个元素为Array的{​​{1}};
  2. [从不发生]函数0调用函数C并覆盖AA的输出;

相反,在第二步中,A被声明为等于A的第一个元素,然后才调用a。由于A是从对a的调用中获取其值的,因此A将是A,结果是:undefined->“不是函数” < / p>

优化

  1. 保持DRY(不要重复自己)-当您看到看起来相同或具有相同结构的代码时,请考虑使其可重用(使其成为函数,类,对象,变量-取决于它)。它使您的代码可读性强且易于调试,但是在很多时候,它节省了对API的调用,重新计算以及因此而节省的时间(尤其是如果您重复I / O)。
  2. 除非绝对必要,否则请不要使用注释(会大大降低可读性-如果您需要其他人来帮助调试代码或自己做代码,这很关键[听起来有些违反直觉,但您会感到惊讶)。
  3. 除非没有选择,否则不要将I / O([undefined]()getRange())放入循环中-除非输入/输出总是很慢,所以通常最好将所有内容加载到内存中并进行处理那里的数据。
  4. 保持一致的作用域:如果声明一个变量,则每个访问器都应该在相同的作用域中或嵌套(例如,不要在getValue()内声明两个同名的变量,将其移到外部作用域)。
  5. 使用TypeScript或至少使用JSDoc-可以使您避免疯狂,同时试图了解您的函数为何期望一种类型并收到另一种类型(就像您的情况一样)[UPD:我还添加了JSDOC注释解决方案]。

我对您的脚本进行了一些优化,看看(请在使用前检查一下,因为我们没有示例数据,所以我无法对其进行测试)。您还可以做更多的事情(尤其是关于if...else中的循环),但这应该是一个开始:

calcsOnColumns2

注释

  1. 尽管现代JavaScript可以帮助您避免该问题,但您应该 除非您确切知道为什么,否则不要覆盖任何变量名 正在这样做(/** * [Your decription here] * @returns {Number[]} */ function invoicePrice() { var ss = SpreadsheetApp.getActiveSpreadsheet(); var subtotalDisplaySheet = ss.getSheetByName('SubtotalDisplay'); // define row to do calculations on var AVals = subtotalDisplaySheet.getRange("A1:A1000").getValues(); var ALast = AVals.filter(String).length; // Set order No. here var orderNoPrev = subtotalDisplaySheet.getRange(ALast - 1, 3).getValue(); var orderNo = subtotalDisplaySheet.getRange(ALast, 3).setValue(orderNoPrev + 1); // invoicePrice the total number of items var itemRange = subtotalDisplaySheet.getRange(ALast, 4, 1, 14).getValues()[0]; // set the values of the constants on the Products page var productsSheet = ss.getSheetByName("Products"); var priceRange = productsSheet.getRange("F1:F1000").getValues(); var pLast = priceRange.filter(String).length; var pGrab = priceRange.splice(0, pLast); var outputInvoicePrice = 0; var weightRange = productsSheet.getRange("V1:V1000").getValues(); var wLast = weightRange.filter(String).length; var wGrab = weightRange.splice(0, wLast); var orderAmounts = subtotalDisplaySheet.getRange(Alast, 17).getValues(); var total = 0; for (var i = 0, len = 13; i <= len; i++) { var nextI = i + 1; var orderAmount = orderAmounts[0][i + 4]; total += orderAmount; var perKGInvoice = pGrab[nextI].map(Number); var weights = wGrab[nextI].map(Number); var casePrice = perKGInvoice * weights; outputInvoicePrice += orderAmount * casePrice; } Logger.log(outputInvoicePrice, ALast, pGrab, wGrab); return [outputInvoicePrice, ALast, pGrab, wGrab]; } /** * Gets values from 5 rows in * a column starting from row 3 * @param {Sheet} sheet * @param {Number} column * @returns {*[]} */ function getGridValues(sheet, column) { var range = sheet.getRange(3, column, 5, 1); return range .getValues() .map(function (row) { return row[0]; }); } /** * [Your decription here] * @returns {Number[]} */ function tiers() { var ss = SpreadsheetApp.getActiveSpreadsheet(); var discountGridSheet = ss.getSheetByName("DiscountGrid"); var invoicePriceCall = invoicePrice(); var outputInvoicePrice = invoicePriceCall[0]; var ALast = invoicePriceCall[1]; var beefDiscount = 0; var sfDiscount = 0; var currentTier = ""; var tierValues = getGridValues(discountGridSheet, 3); var tier1 = tierValues[0]; var tier2 = tierValues[1]; var tier3 = tierValues[2]; var tier4 = tierValues[3]; var tier5 = tierValues[4]; var minNotmet = discountGridSheet.getRange(10, 3).getValue(); var tierBeefDiscountValues = getGridValues(discountGridSheet, 4); var tier1BeefDiscount = tierBeefDiscountValues[0]; var tier2BeefDiscount = tierBeefDiscountValues[1]; var tier3BeefDiscount = tierBeefDiscountValues[2]; var tier4BeefDiscount = tierBeefDiscountValues[3]; var tier5BeefDiscount = tierBeefDiscountValues[4]; var tierSfDiscountValues = getGridValues(discountGridSheet, 5); var tier1SfDiscount = tierSfDiscountValues[0]; var tier2SfDiscount = tierSfDiscountValues[1]; var tier3SfDiscount = tierSfDiscountValues[2]; var tier4SfDiscount = tierSfDiscountValues[3]; var tier5SfDiscount = tierSfDiscountValues[4]; if (outputInvoicePrice < tier1) { beefDiscount = tier1BeefDiscount; sfDiscount = tier1SfDiscount; currentTier = "Minimum Not Met"; } else if (outputInvoicePrice < tier2) { beefDiscount = tier1BeefDiscount; sfDiscount = tier1SfDiscount; currentTier = "Tier 1"; } else if (outputInvoicePrice < tier3) { beefDiscount = tier2BeefDiscount; sfDiscount = tier2SfDiscount; currentTier = "Tier 2"; } else if (outputInvoicePrice < tier4) { beefDiscount = tier3BeefDiscount; sfDiscount = tier3SfDiscount; currentTier = "Tier 3"; } else if (outputInvoicePrice < tier5) { beefDiscount = tier4BeefDiscount; sfDiscount = tier4SfDiscount; currentTier = "Tier 4"; } else { beefDiscount = tier5BeefDiscount; sfDiscount = tier5SfDiscount; currentTier = "Tier 5"; } var subtotalDisplaySheet = ss.getSheetByName("SubtotalDisplay"); var subtotalDisplayRange = subtotalDisplaySheet.getRange(ALast, 20, 3, 1); subtotalDisplayRange.setValues([ [beefDiscount], [sfDiscount], [currentTier] ]); return [beefDiscount, sfDiscount, tier1]; } /** * Foramts amount string * @param {Number} amount * @returns {Function} */ function formatAmount(amount) { return function (discount, caseOrder) { return amount + " cases @" + discount.toFixed(2) + "/kg = ~$" + caseOrder.toFixed(2); }; } /** * Counts sum by discount, amount and weights * @param {Number} amount * @param {Number} weights * @returns {Number} */ function countSum(amount, weights) { return function (discount) { return discount * amount * weights; }; } /** * Counts discount case per Kg * @param {Number} perKG * @returns {Number} */ function countDiscountCase(perKG) { return function (discount) { return perKG - (perKG * discount); }; } /** * [Your decription here] */ function calcsOnColumns2() { var ss = SpreadsheetApp.getActiveSpreadsheet(); var subtotalDisplaySheet = ss.getSheetByName("SubtotalDisplay"); var invoicePriceCall = invoicePrice(); var outputInvoicePrice = invoicePriceCall[0]; var ALast = invoicePriceCall[1]; var priceRange = invoicePriceCall[2]; var weightRange = invoicePriceCall[3]; var tiers = tiers(); var beefDiscount = tiers[0]; var sfDiscount = tiers[1]; var tier1 = tiers[2]; var beefSum = 0; var sfSum = 0; var orderAmounts = subtotalDisplaySheet.getRange(ALast, 17).getValues(); for (var i = 0, len = 13; i <= len; i++) { var orderAmount = orderAmounts[0][i + 4]; var nextI = i + 1; var perKGInvoice = priceRange[nextI].map(Number); var weights = weightRange[nextI].map(Number); var casePrice = perKGInvoice * weights; var subtotalRange = subtotalDisplaySheet.getRange(ALast, i + 32); var formatAmountOrder = formatAmount(orderAmount); var countDisountSum = countSum(orderAmount, weights); var countPerKGCase = countDiscountCase(perKGInvoice); // Split up seafood and beef with if statement: if (i < 9) { var discountCaseBeef = countPerKGCase(beefDiscount); var beefCaseOrder = countDisountSum(discountCaseBeef); beefSum += beefCaseOrder; } else { var discountCaseSF = countPerKGCase(sfDiscount); var sfCaseOrder = countDisountSum(discountCaseSF); sfSum += sfCaseOrder; } if (orderAmount) { subtotalRange.setValue( i < 9 ? formatAmountOrder(discountCaseBeef, beefCaseOrder) : formatAmountOrder(discountCaseSF, sfCaseOrder) ); } if (i == len) { subtotalDisplaySheet.getRange(ALast, 24).setValue(beefSum); subtotalDisplaySheet.getRange(ALast, 25).setValue(sfSum); // if statement to go here if min order size not met var subtotalRange = subtotalDisplaySheet.getRange(ALast, 27); var sumOfSums = beefSum + sfSum; subtotalRange.setValue(sumOfSums > tier1 ? "Minimum order size not met" : sumOfSums); var totalDiscount = outputInvoicePrice - sumOfSums; subtotalDisplaySheet.getRange(ALast, 29).setValue(totalDiscount); subtotalDisplaySheet.getRange(ALast, 30).setValue(outputInvoicePrice); } } }是一个示例,但是功能样式会 说甚至是有问题的。)
  2. 出于可读性考虑,切勿在SO上发布时截断错误消息/代码-知道确切发生的事情对我们帮助您无价之宝(i++ invoicePrice说得更多)。

参考

  1. Hoisting in JavaScript