如何获取对象类型

How to get the object type

本文关键字:类型 取对象 何获      更新时间:2023-09-26

在我的Google Apps脚本应用程序中,我看到以下错误:

脚本已完成,但返回值不是受支持的返回类型

如何找出要返回的值的类型?我试过了:

typeof(obj)

但我被告知的只是一个对象。

仅当缓存为空且从电子表格加载数据时,才会发生此错误。 例如,用户点击页面,获取错误,刷新现在加载页面,因为缓存是在第一次点击时填充的。现在用户可以继续使用该页面,直到缓存失效,然后下一次点击将再次导致此错误。

在我阅读并遵循此文档后,此错误今天开始发生。以前我的脚本在模板中加载数据,现在我重构为使用以下异步加载:

google.script.run

查看了页面中发生的事情,了解为什么从缓存中读取时它有效,我唯一能看到的不同之处在于缓存中的数据是从 JSON 字符串解析的。当缓存为空时,我必须将对象字符串化才能保存到缓存中,因此我不会返回原始对象,而是解析我刚刚创建的字符串并返回该字符串,现在没有错误。

我也不确定错误来自哪里,是应用程序脚本还是 Caja?

解析 JSON 字符串以返回也不是理想的解决方案,这种字符串化/解析对我的原始对象做了什么来消除错误?

当我使用内置调试器检查对象时(在字符串化/解析过程之前和之后),值和类型似乎都与我所能检查

的相同。

这是应用程序脚本中的错误吗?我做错了什么吗?消除此错误的最佳解决方案是什么?

我们可以扩展 JavaScript 对象,让它们告诉我们它们的对象类型,如如何在 JavaScript 中获取对象类型的名称?。但是,这不适用于Google Apps Script对象。

这是我整理的一个技巧,似乎适用于 GAS 对象。我没有尝试过每一个,但许多主要对象确实有效。

function getObjType(obj) {
  var type = typeof(obj);
  if (type === "object") {
    try {
      // Try a dummy method, catch the error
      type = obj.getObjTypeXYZZY();
    } catch (error) {
      // Should be a TypeError - parse the object type from error message
      type = error.message.split(" object ")[1].replace('.','');
    }
  }
  return type;
}

下面是一个测试例程:

function test_getObjType() {
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  Logger.log("Spreadsheet: " + getObjType(spreadsheet));
  var sheet = spreadsheet.getActiveSheet();
  Logger.log("Sheet: " + getObjType(sheet));
  var range = sheet.getActiveCell();
  Logger.log("Range: " + getObjType(range));
  var string = "Hello";
  Logger.log("String: " + getObjType(string));
};

结果是:

[13-12-18 23:23:47:379 EST] Spreadsheet: Spreadsheet
[13-12-18 23:23:47:609 EST] Sheet: Sheet
[13-12-18 23:23:47:626 EST] Range: Range
[13-12-18 23:23:47:626 EST] String: string

我知道这是一个非常古老的帖子,但想让每个发现自己在谷歌推荐下的人都知道该解决方案不再有效。

我正在努力解决同样的问题,并尝试了建议的解决方案。看起来谷歌(再次)决定在不告诉任何人或更新文档的情况下更改其产品的功能。

错误消息不再包含对象类型,因此不是得到"TypeError:无法在对象中找到函数foobar",而是得到"TypeError:在对象中找不到函数foobar<在此处插入toString()的输出>"。

错误消息很可能总是使用 toString() 方法,

并且由于 Google 从 toString() 方法中删除了对象类型,他们也破坏了这种获取对象类型的方式。

我只需要找出对象是数组还是字符串,并找到了一个技巧来解决这个问题。

function getObjType(obj) {
  
  // If the object is an array, this will return the stored value,
  // if the object is a string, this will return only one letter of the string
  var type = obj[0];
  if (type.length == 1) {
    return 'string';
  }
  try {
    type = obj.foobar();
  } catch (error) {
    
    // TypeError no longer contains object type, just return 'array'
    Logger.log(error);
    return 'array';
  }
}

由于最高答案不再有效,我为自己的用例提出了一个黑客解决方案,后来发现Google内置了查找类型的功能。

为了举例说明上下文,如果您要遍历 Google 文档中的段落,并想知道该段落代表的是文本还是图像,则可以执行以下操作:

const childType = paragraph.getChild(0).getType();
if (childType == DocumentApp.ElementType.TEXT) {
  // ...
}
else if (childType == DocumentApp.ElementType.INLINE_IMAGE) {
  // ...
}

有关详细信息,请参阅文档。

我掉进了整个兔子洞,正准备编写一个"猜测类型"函数时,我想起问题始于 Logger 控制台刚刚吐出对象的"类型"名称,而不是带有成员的对象视图。事实证明,脚本类型的默认toString()行为是返回其隐式类型名称:

  const filter = range.createFilter();
  Logger.log(filter.toString() == "Filter"); // true
  Logger.log(filter + "" == "Filter"); // true
  Logger.log(filter == "Filter"); // true

因此,只需将其与隐式类型名称进行比较即可检查脚本类型。我还不知道是否有具有不同toString()行为的类型,所以如果幕后存在差异,也许使用类似 object + "" 的东西更健壮(?

这是我在Google Apps Script中获取对象类型的帮助程序函数:

/**
 *  Returns the object type.
 *
 *  @param {*} obj
 *  @returns {string}
 */
function getObjectType(obj) {
  let type = typeof obj;
  if (type === 'object') {
    if (Array.isArray(obj)) {
      type = 'Array';
    } else if (obj === null) {
      type = 'null';
    } else if (Object.prototype.toString.call(obj.getA1Notation) === '[object Function]') {
      // JSDoc usage: @param {SpreadsheetApp.Range}
      type = 'Range';
    } else if (Object.prototype.toString.call(obj.getActiveCell) === '[object Function]') {
      // JSDoc usage: @param {SpreadsheetApp.Sheet}
      type = 'Sheet';
    } else if (Object.prototype.toString.call(obj) === '[object Object]') {
      // Some other object (this block should come last)
      type = 'Object';
    }
  }
  // Note that NaN (Not a Number) returns type `number`
  return type;
}

随意使用它并根据您的需求扩展它以支持其他电子表格应用程序类。如果确实扩展了它,请尝试选择该类唯一的方法。