exportFunction()

此函式提供了一種安全的方式,將特權範圍內的函式暴露給低特權範圍。這使得特權程式碼(例如擴充套件)能夠與低特權程式碼(例如標準網頁尾本)共享程式碼。從特權程式碼匯出到低特權程式碼的函式可以在低特權程式碼的上下文中被呼叫。

該函式可以像在特權上下文中呼叫一樣訪問其周圍的閉包。

匯出的函式不需要新增到低特權程式碼的全域性 window 物件中;它可以匯出到目標作用域中的任何物件。

請參閱 匯出接受引數的函式,瞭解您匯出的函式是否接受引數時會發生什麼。

語法

js
let exportedFunction = exportFunction(
  func,              // function
  targetScope,       // object
  options            // optional object
);

引數

func

function. 要匯出的函式。

targetScope

object. 要將函式附加到的物件。這不一定是全域性 window 物件;它可以是目標視窗中的一個物件,或者由呼叫者建立的物件。

options 可選

object. 函式的選項。

defineAs 可選

string. 在 targetScope 中函式的名稱。如果省略,則需要將 exportFunction() 的返回值分配給目標作用域中的一個物件。

allowCrossOriginArguments 可選

boolean. 是否檢查匯出函式的引數是否被呼叫者 包含。這允許呼叫者將具有不同源的物件傳遞給匯出函式,然後匯出函式可以利用其特權身份使用該物件進行跨域請求。預設為 false

返回值

在目標上下文中建立的佔位符函式。

匯出接受引數的函式

傳入函式的任何引數都不會被克隆。相反,它們會作為 Xrays 傳遞到特權範圍。

修改引數

物件的 Xray 指的是原始物件。在匯出函式中對引數所做的任何更改都會影響傳入的原始物件。例如:

js
// privileged scope: for example, a content script
function changeMyName(user) {
  user.name = "Bill";
}
exportFunction(changeMyName, window, {
  defineAs: "changeMyName",
});
js
// less-privileged scope: for example, a page script
const user = { name: "Jim" };
const test = document.getElementById("test");
test.addEventListener("click", () => {
  console.log(user.name); // "Jim"
  window.changeMyName(user);
  console.log(user.name); // "Bill"
});

此行為受 Xrays 的常規規則約束。例如,新增到 DOM 節點的 expando 屬性在原始物件中是不可見的。

Xray 過濾和豁免

Xrays 提供對原始物件的過濾檢視。例如,在 JavaScript Object 型別的 Xrays 中,函式是不可見的。如果您需要對原始物件的無過濾訪問,可以 豁免 Xrays

js
// privileged scope: for example, a content script
function logUser(user) {
  // console.log(user.getUser());                 // error
  console.log(user.wrappedJSObject.getUser()); // "Bill"
}
exportFunction(logUser, window, {
  defineAs: "logUser",
});
js
// less-privileged scope: for example, a page script
const user = {
  getUser() {
    return "Bill";
  },
};
const test = document.getElementById("test");
test.addEventListener("click", () => {
  window.logUser(user);
});

有關更多資訊,請參閱 Firefox Source Tree 文件中的 Xray vision

傳遞函式作為引數

如果將函式作為引數傳遞,這些函式也會作為 Xrays 傳遞。由於您可以像普通函式一樣呼叫 Function Xrays,這意味著將回調傳遞給匯出函式是可行的。

js
// privileged scope: for example, a content script
function logUser(getUser) {
  console.log(getUser()); // "Bill"
}
exportFunction(logUser, unsafeWindow, {
  defineAs: "logUser",
});
js
// less-privileged scope: for example, a page script
function getUser() {
  return "Bill";
}
const test = document.getElementById("test");
test.addEventListener("click", () => {
  window.logUser(getUser);
});

跨域檢查

呼叫匯出函式時,將檢查每個引數(包括 this),以確保呼叫者 包含 該引數。這可以防止將跨域物件(例如 WindowLocation)傳遞給特權函式,因為特權程式碼可以完全訪問這些物件,並可能無意中執行危險操作。透過將 { allowCrossOriginArguments: true } 傳遞給 exportFunction 可以覆蓋此規定。

示例

匯出到全域性作用域

此指令碼定義了一個函式,然後將其匯出到內容視窗。

js
// extension-script.js
const salutation = "hello ";
function greetMe(user) {
  return salutation + user;
}
exportFunction(greetMe, window, { defineAs: "foo" });

指令碼可以使用 `defineAs` 以外的方式,將 `exportFunction` 的結果分配給目標作用域中的一個物件。

js
// extension-script.js
const salutation = "hello ";
function greetMe(user) {
  return salutation + user;
}
window.foo = exportFunction(greetMe, window);

無論哪種方式,在內容視窗作用域中執行的程式碼都可以呼叫該函式。

js
// page-script.js
const greeting = foo("alice");
console.log(greeting);
// "hello alice"

匯出到現有的本地物件

呼叫者可以將函式附加到目標上下文中的任何其他物件,而不是將其附加到目標的全域性 window 物件。假設內容視窗定義了一個區域性變數 bar

js
// page-script.js
const bar = {};

現在,擴充套件指令碼可以將函式附加到 bar

js
// extension-script.js
exportFunction(greetMe, window.bar, {
  defineAs: "greetMe",
});
js
// page-script.js
const value = bar.greetMe("bob");
console.log(value);
// "hello bob"

瀏覽器相容性