ใส่รหัสลงในบริบทของหน้าโดยใช้สคริปต์เนื้อหา


480

ฉันเรียนรู้วิธีสร้างส่วนขยาย Chrome ฉันเพิ่งเริ่มพัฒนากิจกรรมเพื่อจับภาพ YouTube ฉันต้องการใช้กับเครื่องเล่นแฟลชของ YouTube (ภายหลังฉันจะพยายามทำให้มันเข้ากันได้กับ HTML5)

manifest.json:

{
    "name": "MyExtension",
    "version": "1.0",
    "description": "Gotta catch Youtube events!",
    "permissions": ["tabs", "http://*/*"],
    "content_scripts" : [{
        "matches" : [ "www.youtube.com/*"],
        "js" : ["myScript.js"]
    }]
}

MyScript.js:

function state() { console.log("State Changed!"); }
var player = document.getElementById("movie_player");
player.addEventListener("onStateChange", "state");
console.log("Started!");

ปัญหาคือว่าคอนโซลให้ฉัน"เริ่มต้น!" แต่ไม่มี"สถานะเปลี่ยน!" เมื่อฉันเล่น / หยุดวิดีโอ YouTube ชั่วคราว

เมื่อใส่รหัสนี้ในคอนโซลมันทำงานได้ ผมทำอะไรผิดหรือเปล่า?


14
ลองลบเครื่องหมายคำพูดรอบชื่อฟังก์ชันของคุณ:player.addEventListener("onStateChange", state);
Eduardo

2
เป็นที่น่าสังเกตว่าเมื่อเขียนการแข่งขันอย่าลืมที่จะรวมhttps://หรือhttp://สิ่งนี้www.youtube.com/*จะไม่อนุญาตให้คุณแพ็คส่วนขยายและจะโยนข้อผิดพลาดตัวแยกโครงการที่ขาดหายไป
Nilay Vishwakarma

คำตอบ:


874

สคริปต์เนื้อหาจะดำเนินการใน"โลกโดดเดี่ยว" สภาพแวดล้อม คุณต้องฉีดstate()วิธีการของคุณลงในหน้าตัวเอง

เมื่อคุณต้องการที่จะใช้อย่างใดอย่างหนึ่งของchrome.*APIs ในสคริปต์คุณจะต้องดำเนินการจัดการเหตุการณ์พิเศษที่อธิบายไว้ในคำตอบนี้: ส่วนขยายของ Chrome - เรียกข้อความต้นฉบับของ

มิฉะนั้นหากคุณไม่จำเป็นต้องใช้chrome.*API ฉันขอแนะนำอย่างยิ่งให้ฉีดรหัส JS ของคุณทั้งหมดในหน้าผ่านการเพิ่ม<script>แท็ก:

สารบัญ

  • วิธีที่ 1: ฉีดไฟล์อื่น
  • วิธีที่ 2: ฉีดรหัสฝังตัว
  • วิธีที่ 2b: การใช้ฟังก์ชัน
  • วิธีที่ 3: การใช้เหตุการณ์แบบอินไลน์
  • ค่าแบบไดนามิกในรหัสที่ฉีด

วิธีที่ 1: ฉีดไฟล์อื่น

นี่เป็นวิธีที่ง่ายที่สุด / ดีที่สุดเมื่อคุณมีรหัสจำนวนมาก รวมรหัส JS จริงของคุณลงในไฟล์ภายในส่วนขยายของคุณscript.jsด้วย จากนั้นให้สคริปต์เนื้อหาของคุณเป็นดังนี้ (อธิบายที่นี่: Google Chome“ จาวาสคริปต์ทางลัด” จาวาสคริปต์ที่กำหนดเอง ):

var s = document.createElement('script');
// TODO: add "script.js" to web_accessible_resources in manifest.json
s.src = chrome.runtime.getURL('script.js');
s.onload = function() {
    this.remove();
};
(document.head || document.documentElement).appendChild(s);

หมายเหตุ: หากคุณใช้วิธีนี้script.jsไฟล์ที่ถูกฉีดจะต้องถูกเพิ่มเข้าไปใน"web_accessible_resources"ส่วน ( ตัวอย่าง ) หากคุณไม่ใช้ Chrome จะปฏิเสธที่จะโหลดสคริปต์ของคุณและแสดงข้อผิดพลาดต่อไปนี้ในคอนโซล:

กำลังปฏิเสธการโหลด chrome-extension: // [EXTENSIONID] /script.js ทรัพยากรจะต้องอยู่ในรายการรายการ web_accessible_resources เพื่อที่จะโหลดหน้าเว็บที่อยู่นอกส่วนขยาย

วิธีที่ 2: ฉีดรหัสฝังตัว

วิธีนี้มีประโยชน์เมื่อคุณต้องการเรียกใช้โค้ดขนาดเล็กอย่างรวดเร็ว (ดูเพิ่มเติมที่: วิธีปิดการใช้งานปุ่มลัด facebook ด้วยส่วนขยายของ Chrome )

var actualCode = `// Code here.
// If you want to use a variable, use $ and curly braces.
// For example, to use a fixed random number:
var someFixedRandomValue = ${ Math.random() };
// NOTE: Do not insert unsafe variables in this way, see below
// at "Dynamic values in the injected code"
`;

var script = document.createElement('script');
script.textContent = actualCode;
(document.head||document.documentElement).appendChild(script);
script.remove();

หมายเหตุ: รองรับเทมเพลตตัวอักษรใน Chrome 41 ขึ้นไป หากคุณต้องการให้ส่วนขยายทำงานใน Chrome 40- ให้ใช้:

var actualCode = ['/* Code here. Example: */' + 'alert(0);',
                  '// Beware! This array have to be joined',
                  '// using a newline. Otherwise, missing semicolons',
                  '// or single-line comments (//) will mess up your',
                  '// code ----->'].join('\n');

วิธีที่ 2b: การใช้ฟังก์ชัน

สำหรับโค้ดขนาดใหญ่การอ้างอิงสตริงนั้นไม่สามารถทำได้ แทนที่จะใช้อาร์เรย์คุณสามารถใช้ฟังก์ชันและสร้างสตริงได้:

var actualCode = '(' + function() {
    // All code is executed in a local scope.
    // For example, the following does NOT overwrite the global `alert` method
    var alert = null;
    // To overwrite a global variable, prefix `window`:
    window.alert = null;
} + ')();';
var script = document.createElement('script');
script.textContent = actualCode;
(document.head||document.documentElement).appendChild(script);
script.remove();

วิธีนี้ใช้งานได้เนื่องจากตัว+ดำเนินการบนสตริงและฟังก์ชันแปลงวัตถุทั้งหมดเป็นสตริง หากคุณตั้งใจจะใช้รหัสมากกว่าหนึ่งครั้งคุณควรสร้างฟังก์ชันเพื่อหลีกเลี่ยงการทำซ้ำรหัส การใช้งานอาจมีลักษณะดังนี้:

function injectScript(func) {
    var actualCode = '(' + func + ')();'
    ...
}
injectScript(function() {
   alert("Injected script");
});

หมายเหตุ: เนื่องจากฟังก์ชั่นนั้นเป็นแบบอนุกรมขอบเขตดั้งเดิมและคุณสมบัติที่ถูกผูกไว้ทั้งหมดจะหายไป!

var scriptToInject = function() {
    console.log(typeof scriptToInject);
};
injectScript(scriptToInject);
// Console output:  "undefined"

วิธีที่ 3: การใช้เหตุการณ์แบบอินไลน์

บางครั้งคุณต้องการเรียกใช้รหัสบางอย่างทันทีเช่นเรียกใช้รหัสก่อนที่<head>จะสร้างองค์ประกอบ สิ่งนี้สามารถทำได้โดยการแทรก<script>แท็กด้วยtextContent(ดูวิธี 2 / 2b)

ทางเลือกอื่นแต่ไม่แนะนำคือให้ใช้เหตุการณ์แบบอินไลน์ ไม่แนะนำเนื่องจากหากหน้ากำหนดนโยบายความปลอดภัยเนื้อหาที่ห้ามสคริปต์แบบอินไลน์ผู้ฟังเหตุการณ์แบบอินไลน์จะถูกบล็อก สคริปต์แบบอินไลน์ฉีดโดยส่วนขยายในขณะที่ยังคงทำงาน หากคุณยังต้องการใช้เหตุการณ์แบบอินไลน์นี่คือวิธี:

var actualCode = '// Some code example \n' + 
                 'console.log(document.documentElement.outerHTML);';

document.documentElement.setAttribute('onreset', actualCode);
document.documentElement.dispatchEvent(new CustomEvent('reset'));
document.documentElement.removeAttribute('onreset');

หมายเหตุ: วิธีการนี้จะถือว่าไม่มีผู้ฟังเหตุการณ์ระดับโลกรายอื่นที่จัดการกับresetเหตุการณ์ หากมีคุณยังสามารถเลือกหนึ่งในกิจกรรมระดับโลกอื่น ๆ เพียงเปิดคอนโซล JavaScript (F12) พิมพ์document.documentElement.onและเลือกกิจกรรมที่มี

ค่าแบบไดนามิกในรหัสที่ฉีด

ในบางครั้งคุณต้องส่งตัวแปรตามอำเภอใจไปยังฟังก์ชันที่ฉีด ตัวอย่างเช่น:

var GREETING = "Hi, I'm ";
var NAME = "Rob";
var scriptToInject = function() {
    alert(GREETING + NAME);
};

ในการฉีดโค้ดนี้คุณจะต้องส่งตัวแปรเป็นอาร์กิวเมนต์ไปยังฟังก์ชันที่ไม่ระบุตัวตน อย่าลืมนำไปใช้อย่างถูกต้อง! ต่อไปนี้จะไม่ทำงาน:

var scriptToInject = function (GREETING, NAME) { ... };
var actualCode = '(' + scriptToInject + ')(' + GREETING + ',' + NAME + ')';
// The previous will work for numbers and booleans, but not strings.
// To see why, have a look at the resulting string:
var actualCode = "(function(GREETING, NAME) {...})(Hi, I'm ,Rob)";
//                                                 ^^^^^^^^ ^^^ No string literals!

การแก้ปัญหาคือการใช้JSON.stringifyก่อนที่จะผ่านการโต้แย้ง ตัวอย่าง:

var actualCode = '(' + function(greeting, name) { ...
} + ')(' + JSON.stringify(GREETING) + ',' + JSON.stringify(NAME) + ')';

หากคุณมีตัวแปรหลายตัวมันควรใช้JSON.stringifyเพียงครั้งเดียวเพื่อปรับปรุงความสามารถในการอ่านดังนี้:

...
} + ')(' + JSON.stringify([arg1, arg2, arg3, arg4]) + ')';

81
คำตอบนี้ควรเป็นส่วนหนึ่งของเอกสารอย่างเป็นทางการ เอกสารทางการควรจัดส่งตามวิธีที่แนะนำ -> 3 วิธีในการทำสิ่งเดียวกัน ... ผิดหรือเปล่า?
Mars Robertson

7
@ Qantas94Heavy CSP นามสกุลของไม่ได้ส่งผลกระทบต่อสคริปต์เนื้อหา เฉพาะCSP ของหน้าเว็บเท่านั้นที่เกี่ยวข้อง วิธีที่ 1 สามารถบล็อกได้โดยใช้script-srcคำสั่งที่แยกแหล่งที่มาของส่วนขยายวิธีที่ 2 สามารถบล็อกได้โดยใช้ CSP ที่ยกเว้น "ไม่ปลอดภัยแบบอินไลน์" `
Rob W

3
script.parentNode.removeChild(script);มีคนถามว่าทำไมฉันลบแท็กสคริปต์ที่ใช้ เหตุผลของฉันคือทำเพราะฉันชอบทำความสะอาด เมื่อแทรกสคริปต์แบบอินไลน์ในเอกสารสคริปต์จะถูกดำเนินการทันทีและ<script>สามารถลบแท็กได้อย่างปลอดภัย
Rob W

9
วิธีอื่น: ใช้location.href = "javascript: alert('yeah')";ที่ใดก็ได้ในสคริปต์เนื้อหาของคุณ ง่ายกว่าสำหรับตัวอย่างโค้ดสั้น ๆ และสามารถเข้าถึงออบเจ็กต์ JS ของหน้าเว็บได้
Métoule

3
@ChrisP javascript:โปรดใช้ความระมัดระวังในการใช้ รหัสที่ครอบคลุมหลายบรรทัดอาจไม่ทำงานอย่างที่คาดไว้ เส้นความคิดเห็น ( //) location.href = 'javascript:// Do something <newline> alert(0);';จะตัดส่วนที่เหลือดังนั้นนี้จะล้มเหลว: สิ่งนี้สามารถหลีกเลี่ยงได้โดยทำให้แน่ใจว่าคุณใช้ความคิดเห็นแบบหลายบรรทัด อีกสิ่งที่ต้องระวังคือผลลัพธ์ของนิพจน์ควรเป็นโมฆะ javascript:window.x = 'some variable';จะทำให้เอกสารยกเลิกการโหลดและถูกแทนที่ด้วยวลี 'ตัวแปรบางตัว' <script>หากใช้อย่างถูกต้องก็ย่อมเป็นทางเลือกที่น่าสนใจ
Rob W

61

สิ่งเดียวเท่านั้น หายไป ซ่อนจากคำตอบที่ยอดเยี่ยมของ Rob W คือวิธีการสื่อสารระหว่างสคริปต์หน้าฉีดและสคริปต์เนื้อหา

ในด้านการรับ (สคริปต์เนื้อหาของคุณหรือสคริปต์หน้าฉีด) เพิ่มฟังเหตุการณ์:

document.addEventListener('yourCustomEvent', function (e) {
  var data = e.detail;
  console.log('received', data);
});

ที่ด้านผู้ริเริ่ม (สคริปต์เนื้อหาหรือสคริปต์หน้าฉีด) ส่งเหตุการณ์:

var data = {
  allowedTypes: 'those supported by structured cloning, see the list below',
  inShort: 'no DOM elements or classes/functions',
};

document.dispatchEvent(new CustomEvent('yourCustomEvent', { detail: data }));

หมายเหตุ:

  • การส่งข้อความของ DOM ใช้อัลกอริทึมการโคลนที่มีโครงสร้างซึ่งสามารถถ่ายโอนข้อมูลบางประเภทเท่านั้นนอกเหนือจากค่าดั้งเดิม มันไม่สามารถส่งอินสแตนซ์ของคลาสหรือฟังก์ชันหรือองค์ประกอบ DOM
  • ใน Firefox เพื่อส่งวัตถุ (เช่นไม่ใช่ค่าดั้งเดิม) จากสคริปต์เนื้อหาไปยังบริบทของหน้าคุณต้องทำการโคลนนิ่งมันลงในเป้าหมายอย่างชัดเจนโดยใช้cloneInto(ฟังก์ชั่นในตัว) มิฉะนั้นจะล้มเหลวด้วยข้อผิดพลาดการละเมิดความปลอดภัย .

    document.dispatchEvent(new CustomEvent('yourCustomEvent', {
      detail: cloneInto(data, document.defaultView),
    }));

ฉันได้เชื่อมโยงจริงโค้ดและคำอธิบายที่บรรทัดที่สองของคำตอบของฉันเพื่อstackoverflow.com/questions/9602022/...
Rob W

1
คุณมีการอ้างอิงสำหรับวิธีการที่อัปเดตของคุณแล้ว (เช่นรายงานข้อผิดพลาดหรือกรณีทดสอบหรือไม่) ตัวCustomEventสร้างใช้แทนdocument.createEventAPI ที่เลิกใช้แล้ว
Rob W

สำหรับฉัน 'dispatchEvent (CustomEvent ใหม่ ... ' ใช้งานได้ฉันมี Chrome 33 นอกจากนี้ยังไม่ได้ผลเพราะฉันเขียน addEventListener หลังจากฉีดรหัส js
jscripter

ระมัดระวังเป็นพิเศษเกี่ยวกับสิ่งที่คุณส่งผ่านเป็นพารามิเตอร์ตัวที่CustomEventสองของคุณไปยังตัวสร้าง ฉันพบกับความสับสน 2 อย่าง: 1. เพียงใส่เครื่องหมายคำพูดเดี่ยวรอบ 'รายละเอียด' ทำให้ค่างงงวยnullเมื่อได้รับจากผู้ฟังของสคริปต์เนื้อหาของฉัน 2. ที่สำคัญกว่าด้วยเหตุผลบางอย่างที่ผมต้องJSON.parse(JSON.stringify(myData))หรืออื่น ๆ nullที่มันมากเกินไปก็จะกลายเป็น ให้สิ่งนี้แก่ฉันดูเหมือนว่าการเรียกร้องของนักพัฒนา Chromium ต่อไปนี้ - ว่าอัลกอริทึม "โครงสร้างที่เป็นโคลน" ถูกใช้โดยอัตโนมัติ - ไม่เป็นความจริง bugs.chromium.org/p/chromium/issues/detail?id=260378#c18
jdunk

ฉันคิดว่าวิธีที่เป็นทางการคือใช้ window.postMessage: developer.chrome.com/extensions/…
Enrique

9

ฉันยังประสบปัญหาในการสั่งซื้อสคริปต์ที่โหลดซึ่งแก้ไขด้วยการโหลดสคริปต์ตามลำดับ โหลดจะขึ้นอยู่กับคำตอบของร็อบ W

function scriptFromFile(file) {
    var script = document.createElement("script");
    script.src = chrome.extension.getURL(file);
    return script;
}

function scriptFromSource(source) {
    var script = document.createElement("script");
    script.textContent = source;
    return script;
}

function inject(scripts) {
    if (scripts.length === 0)
        return;
    var otherScripts = scripts.slice(1);
    var script = scripts[0];
    var onload = function() {
        script.parentNode.removeChild(script);
        inject(otherScripts);
    };
    if (script.src != "") {
        script.onload = onload;
        document.head.appendChild(script);
    } else {
        document.head.appendChild(script);
        onload();
    }
}

ตัวอย่างการใช้งานจะเป็น:

var formulaImageUrl = chrome.extension.getURL("formula.png");
var codeImageUrl = chrome.extension.getURL("code.png");

inject([
    scriptFromSource("var formulaImageUrl = '" + formulaImageUrl + "';"),
    scriptFromSource("var codeImageUrl = '" + codeImageUrl + "';"),
    scriptFromFile("EqEditor/eq_editor-lite-17.js"),
    scriptFromFile("EqEditor/eq_config.js"),
    scriptFromFile("highlight/highlight.pack.js"),
    scriptFromFile("injected.js")
]);

ที่จริงแล้วฉันค่อนข้างใหม่กับ JS ดังนั้นอย่าลังเลที่จะ ping ฉันไปยังวิธีที่ดีกว่า


3
วิธีแทรกสคริปต์นี้ไม่ค่อยดีนักเนื่องจากคุณสร้างมลภาวะเป็นเนมสเปซของหน้าเว็บ หากหน้าเว็บใช้ตัวแปรที่เรียกว่าformulaImageUrlหรือแสดงว่าcodeImageUrlคุณกำลังทำลายฟังก์ชันการทำงานของหน้าเว็บอย่างมีประสิทธิภาพ หากคุณต้องการส่งตัวแปรไปยังหน้าเว็บฉันขอแนะนำให้แนบข้อมูลกับองค์ประกอบสคริปต์ ( e.g. script.dataset.formulaImageUrl = formulaImageUrl;) และใช้เช่น(function() { var dataset = document.currentScript.dataset; alert(dataset.formulaImageUrl;) })();ในสคริปต์เพื่อเข้าถึงข้อมูล
Rob W

@ RobW ขอบคุณสำหรับบันทึกย่อของคุณแม้ว่าจะเป็นเรื่องเกี่ยวกับตัวอย่างมากขึ้น คุณช่วยอธิบายให้ชัดเจนหน่อยได้datasetไหมว่าทำไมฉันถึงควรใช้ IIFE แทนที่จะได้รับ?
Dmitry Ginzburg

4
document.currentScriptชี้ไปที่แท็กสคริปต์ขณะที่กำลังดำเนินการเท่านั้น หากคุณต้องการเข้าถึงแท็กสคริปต์และ / หรือคุณสมบัติ / คุณสมบัติ (เช่นdataset) คุณต้องเก็บไว้ในตัวแปร เราต้องการ IIFE ในการปิดการจัดเก็บตัวแปรนี้โดยไม่ทำให้เกิดมลภาวะทั่วโลก
Rob W

@ RobW ยอดเยี่ยม! แต่เราไม่สามารถใช้ชื่อตัวแปรบางตัวได้ซึ่งแทบจะไม่ตัดกับชื่อเดิม มันไม่ใช่เรื่องไร้สาระหรือเราอาจมีปัญหาอื่นอีก
Dmitry Ginzburg

2
คุณทำได้ แต่ค่าใช้จ่ายในการใช้ IIFE นั้นเล็กน้อยดังนั้นฉันไม่เห็นเหตุผลที่จะชอบมลภาวะในเนมสเปซมากกว่า IIFE ฉันให้ความสำคัญอย่างแน่นอนว่าฉันจะไม่แยกหน้าเว็บของผู้อื่นในทางใดทางหนึ่งและความสามารถในการใช้ชื่อตัวแปรแบบสั้น ข้อดีอีกประการของการใช้ IIFE คือคุณสามารถออกจากสคริปต์ก่อนหน้านี้ได้ถ้าต้องการ ( return;)
Rob W

6

ในสคริปต์เนื้อหาฉันเพิ่มแท็กสคริปต์ไว้ที่ส่วนหัวซึ่งผูกตัวจัดการ 'onmessage' ไว้ภายในตัวจัดการที่ฉันใช้ eval ประมวลผลโค้ด ในสคริปต์เนื้อหาของบูธฉันใช้ตัวจัดการข้อความด้วยดังนั้นฉันจึงได้รับการสื่อสารสองทาง Chrome เอกสาร

//Content Script

var pmsgUrl = chrome.extension.getURL('pmListener.js');
$("head").first().append("<script src='"+pmsgUrl+"' type='text/javascript'></script>");


//Listening to messages from DOM
window.addEventListener("message", function(event) {
  console.log('CS :: message in from DOM', event);
  if(event.data.hasOwnProperty('cmdClient')) {
    var obj = JSON.parse(event.data.cmdClient);
    DoSomthingInContentScript(obj);
 }
});

pmListener.js เป็นผู้ฟังข้อความที่โพสต์

//pmListener.js

//Listen to messages from Content Script and Execute Them
window.addEventListener("message", function (msg) {
  console.log("im in REAL DOM");
  if (msg.data.cmnd) {
    eval(msg.data.cmnd);
  }
});

console.log("injected To Real Dom");

ด้วยวิธีนี้ฉันสามารถสื่อสาร 2 ทางระหว่าง CS กับ Real Dom มันมีประโยชน์มากเช่นถ้าคุณต้องการฟังเหตุการณ์ webscoket หรือในตัวแปรหน่วยความจำหรือเหตุการณ์


1

คุณสามารถใช้ฟังก์ชั่นยูทิลิตี้ที่ฉันสร้างขึ้นเพื่อวัตถุประสงค์ในการใช้งานโค้ดในบริบทของหน้าเว็บและเรียกคืนค่าที่ส่งคืน

สิ่งนี้ทำได้โดยการเรียงลำดับฟังก์ชั่นเป็นสตริงและฉีดเข้าไปยังเว็บเพจ

ยูทิลิตี้ที่ได้คือสามารถใช้ได้ที่นี่บน GitHub

ตัวอย่างการใช้งาน -



// Some code that exists only in the page context -
window.someProperty = 'property';
function someFunction(name = 'test') {
    return new Promise(res => setTimeout(()=>res('resolved ' + name), 1200));
}
/////////////////

// Content script examples -

await runInPageContext(() => someProperty); // returns 'property'

await runInPageContext(() => someFunction()); // returns 'resolved test'

await runInPageContext(async (name) => someFunction(name), 'with name' ); // 'resolved with name'

await runInPageContext(async (...args) => someFunction(...args), 'with spread operator and rest parameters' ); // returns 'resolved with spread operator and rest parameters'

await runInPageContext({
    func: (name) => someFunction(name),
    args: ['with params object'],
    doc: document,
    timeout: 10000
} ); // returns 'resolved with params object'


0

หากคุณต้องการฉีดฟังก์ชั่นบริสุทธิ์แทนข้อความคุณสามารถใช้วิธีนี้:

function inject(){
    document.body.style.backgroundColor = 'blue';
}

// this includes the function as text and the barentheses make it run itself.
var actualCode = "("+inject+")()"; 

document.documentElement.setAttribute('onreset', actualCode);
document.documentElement.dispatchEvent(new CustomEvent('reset'));
document.documentElement.removeAttribute('onreset');

และคุณสามารถส่งพารามิเตอร์ (โชคไม่ดีที่ไม่มีวัตถุและอาร์เรย์สามารถทำให้เป็นสตริงได้) ไปยังฟังก์ชัน เพิ่มเข้าไปใน baretheses เช่นโดย:

function inject(color){
    document.body.style.backgroundColor = color;
}

// this includes the function as text and the barentheses make it run itself.
var color = 'yellow';
var actualCode = "("+inject+")("+color+")"; 


นี่มันเจ๋งทีเดียว ... แต่รุ่นที่สองซึ่งมีตัวแปรสำหรับสีใช้งานไม่ได้สำหรับฉัน ... ฉันได้รับ 'ไม่รู้จัก' และรหัสพ่นข้อผิดพลาด ... ไม่เห็นว่าเป็นตัวแปร
11
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.