簡體   English   中英

如何遍歷 v8 中全局對象(庫)的所有屬性/函數?

[英]How to iterate through all properties/functions of a global object(library) in v8?

Google 應用程序腳本提供了一個庫功能,如果您包含項目密鑰,則會將一個庫添加為全局 object。 我正在尋找迭代添加庫的所有功能。 這曾經在帶有for...in循環的引擎中是可能的。 但是我無法遍歷引擎中庫的任何屬性。

文件

在 V8 運行時中,項目及其庫在不同的執行上下文中運行,因此具有不同的全局和原型鏈。

誰能解釋這個 object 是如何創建的或如何訪問它的所有屬性?

項目一:

function testLib(prop = 'main') {
  const isEnumerable = MyLibrary.propertyIsEnumerable(prop);
  const isOwnProperty = MyLibrary.hasOwnProperty(prop);
  console.info({ isEnumerable, isOwnProperty }); // { isEnumerable: false, isOwnProperty: true }
  console.info(prop in MyLibrary);//true
  for (const property in MyLibrary) {
    //loop doesn't start
    console.info(property);
  }
  console.info(Object.getOwnPropertyDescriptor(MyLibrary, prop)); //logs expected  data:
  /*{ value: [Function: main],
  writable: true,
  enumerable: false,
  configurable: true }*/
  console.log(Object.getOwnPropertyDescriptors(MyLibrary)); //actual: {} Expected: array of all functions including `main`
}

function testPropDescriptors() {
  const obj = { prop1: 1, b: 2 };
  console.log(Object.getOwnPropertyDescriptors(obj)); //logs expected data
  /*{prop1: { value: 1, writable: true, enumerable: true, configurable: true },
  b: { value: 2, writable: true, enumerable: true, configurable: true } }*/
}

我的圖書館(項目 B):

function main(){}
function onEdit(){}

為了重現,

  • 通過單擊此處創建一個新項目 - 例如,項目 A
  • 創建另一個腳本項目(比如項目 B):
  • 將上面的腳本復制粘貼到項目A中,select testLib function 然后點擊運行

問題和解決方法:

我一直在尋找在啟用 V8 下從客戶端直接檢索庫端的屬性和函數的方法。 但不幸的是,我仍然找不到它。 因此,就我而言,我使用了兩種解決方法。

  1. 使用 Apps Script API 和/或 Drive API 檢索所有腳本。

  2. 將屬性和函數包裝在 object 中。

通過上述變通方法,可以從客戶端檢索庫端的屬性和函數。

解決方法 1:

在此解決方法中,使用 Apps Script API 和 Drive API 檢索庫端的所有腳本。

示例腳本 1:

在此示例中,使用了 Apps 腳本 API。 因此,當您使用此腳本時,請將 Google Cloud Platform Project 鏈接到 Google Apps Script Project。 參考並且,請在 API 控制台啟用應用程序腳本 API。

const projectIdOflibrary = "###"; // Please set the project ID of the library.

const url = `https://script.googleapis.com/v1/projects/${projectIdOflibrary}/content`;
const res = UrlFetchApp.fetch(url, {headers: {authorization: "Bearer " + ScriptApp.getOAuthToken()}});
const obj = JSON.parse(res.getContentText())
const functions = obj.files.reduce((ar, o) => {
  if (o.name != "appsscript") ar.push(o);
  return ar;
}, []);
console.log(functions)
// console.log(functions.map(({functionSet}) => functionSet.values)) // When you want to see the function names, you can use this line.
  • 當此腳本用於您的庫腳本時, console.log(functions.flatMap(({functionSet}) => functionSet.values))返回[ { name: 'main' }, { name: 'onEdit' } ]

  • 在這種情況下,即使庫是 Google Docs 的容器綁定腳本,該腳本也可以工作。

示例腳本 2:

在此示例中,使用了驅動器 API。 因此,當您使用此腳本時,請在 Google 高級服務中啟用 Drive API。

const projectIdOflibrary = "###"; // Please set the project ID of the library.

const url = `https://www.googleapis.com/drive/v3/files/${projectIdOflibrary}/export?mimeType=application%2Fvnd.google-apps.script%2Bjson`;
const res = UrlFetchApp.fetch(url, {headers: {authorization: "Bearer " + ScriptApp.getOAuthToken()}});
const obj = JSON.parse(res.getContentText())
const functions = obj.files.reduce((ar, o) => {
  if (o.name != "appsscript") ar.push(o.source);
  return ar;
}, []);
console.log(functions)
  • 當此腳本用於您的庫腳本時, console.log(functions)返回[ 'function main(){}\nfunction onEdit(){}\n' ]

  • 在這種情況下,不會自動解析 function 名稱。 但 Google Apps Script Project 不需要與 Google Cloud Platform Project 鏈接。 但是,當庫是 Google Docs 的容器綁定腳本時,不能使用該腳本。 在這種情況下,當庫僅為獨立類型時,可以使用此腳本。 請注意這一點。

解決方法 2:

在此解決方法中,庫端的屬性和函數使用 object 進行包裝。

示例腳本:庫端

var sample1 = {
  method1: function() {},
  method2: function() {}
};


var sample2 = class sample2 {
  constructor() {
    this.sample = "sample";
  }

  method1() {
    return this.sample;
  }
}

示例腳本:客戶端

function myFunction() {
  const res1 = MyLibrary.sample1;
  console.log(res1)

  const res2 = Object.getOwnPropertyNames(MyLibrary.sample2.prototype);
  console.log(res2)
}
  • 在這種情況下, console.log(res1)console.log(res2)分別返回{ method1: [Function: method1], method2: [Function: method2] }[ 'constructor', 'method1' ]

參考:

Google Apps 腳本是 V8 的自定義嵌入,因此它使用 V8 C++ API 來創建“魔法”對象。 最終結果類似於代理:如果您知道屬性的名稱,則可以檢索它; 但是沒有內置的方法來枚舉庫中的可用函數。 (我不知道為什么它是這樣設計的。)

如果您控制有問題的庫,一種可能的解決方法是從那里導出函數列表:

// MyLibrary:
Object.defineProperty(this, "global", {value: this});
function getExports() {
  let result = [];
  let descriptors = Object.getOwnPropertyDescriptors(global);
  for (let p in descriptors) {
    if (descriptors[p].enumerable) result.push(p);
  }
  return result;
}

// main project:
console.log(MyLibrary.getExports());

(如果您不控制圖書館,@Tanaike 的回答會提供一些建議。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM