Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> HTML

HTML DOM Script Object - จัดการ script element ด้วย JavaScript

วัตถุ HTMLScriptElement แทนแท็ก <script> ใน DOM ใช้สร้าง โหลด และจัดการสคริปต์ไดนามิก รวมถึงควบคุมการโหลดแบบ async/defer

การสร้าง script element

const script = document.createElement('script');

คุณสมบัติสำคัญของ Script Object

คุณสมบัติ คำอธิบาย ประเภท
src URL ของไฟล์สคริปต์ภายนอก Read/Write
type MIME type (default: "text/javascript") Read/Write
async โหลดแบบ asynchronous (ไม่บล็อก parsing) Read/Write (Boolean)
defer เลื่อนการรันจนกว่า HTML parsing จบ Read/Write (Boolean)
crossOrigin CORS setting: "anonymous", "use-credentials" Read/Write
text เนื้อหาสคริปต์ inline (text content) Read/Write
integrity Subresource Integrity hash Read/Write
referrerPolicy Referrer policy สำหรับ request Read/Write
noModule ไม่รันในเบราว์เซอร์ที่รองรับ module Read/Write (Boolean)
แก้ไขจากต้นฉบับ: ตารางคุณสมบัติในต้นฉบับมีคำอธิบายผิดบางส่วน (เช่น defer อธิบายว่า src, charset ขาดหายไป) - ตารางข้างต้นแก้ไขแล้ว

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

<!DOCTYPE html>
<html>
<head>
  <style>
    body { text-align: center; font-family: sans-serif; padding: 2rem; background: #fff; color: #0197F6; }
    h1 { color: #23CE6B; }
    .btn { 
      background: #fff; 
      border: 2px dashed #0197F6; 
      color: #0197F6; 
      padding: 12px 24px; 
      border-radius: 6px; 
      cursor: pointer; 
      font-weight: bold;
      width: 60%; max-width: 300px;
      display: block;
      margin: 1rem auto;
      transition: all 0.2s;
    }
    .btn:hover { background: #0197F6; color: white; }
  </style>
</head>
<body>
  <h1>DOM Script Object Demo</h1>
  <p>คลิกปุ่มเพื่อสร้าง <script> element แบบไดนามิก</p>
  
  <button class="btn" onclick="createInlineScript()">สร้าง Inline Script</button>
  <button class="btn" onclick="createExternalScript()">โหลด External Script</button>
  <button class="btn" onclick="createModuleScript()">สร้าง ES Module Script</button>
  
  <div id="log" style="margin-top: 2rem; text-align: left; max-width: 600px; margin-left: auto; margin-right: auto; font-family: monospace; background: #f5f5f5; padding: 1rem; border-radius: 8px;"></div>
  
  <script>
    function log(msg) {
      const el = document.getElementById('log');
      el.textContent += '\n' + new Date().toLocaleTimeString() + ' - ' + msg;
      el.scrollTop = el.scrollHeight;
    }
    
    function createInlineScript() {
      const script = document.createElement('script');
      script.text = "log('Inline script executed!'); confirm('Inline script รันแล้ว!')";
      document.body.appendChild(script);
      log('สร้าง inline script');
    }
    
    function createExternalScript() {
      const script = document.createElement('script');
      script.src = 'https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js';
      script.async = true;
      script.onload = () => log('External script loaded: lodash');
      script.onerror = () => log('External script failed to load');
      document.head.appendChild(script);
      log('เริ่มโหลด external script (async)');
    }
    
    function createModuleScript() {
      const script = document.createElement('script');
      script.type = 'module';
      script.text = `
        import { shuffle } from 'https://cdn.jsdelivr.net/npm/lodash-es@4.17.21/lodash.esm.js';
        log('ES Module loaded, shuffle([1,2,3]) = ' + JSON.stringify(shuffle([1,2,3])));
      `;
      document.body.appendChild(script);
      log('สร้าง ES module script');
    }
  </script>
</body>
</html>

async vs defer vs module

<!-- โหลดแบบปกติ - บล็อก parsing จนโหลดและรันเสร็จ -->
<script src="app.js"></script>

<!-- async - โหลดขนานกัน รันทันทีที่โหลดเสร็จ (ลำดับไม่รับประกัน) -->
<script src="analytics.js" async></script>

<!-- defer - โหลดขนานกัน รันหลัง parsing จบ ตามลำดับ -->
<script src="app.js" defer></script>

<!-- module - ES6 module (defer โดยอัตโนมัติ) -->
<script type="module" src="app.mjs"></script>

<!-- nomodule - fallback สำหรับเบราว์เซอร์เก่า -->
<script nomodule src="legacy.js"></script>

Dynamic Script Loading Patterns

// 1. Load script with Promise
function loadScript(src, options = {}) {
  return new Promise((resolve, reject) => {
    const script = document.createElement('script');
    script.src = src;
    script.async = options.async !== false;
    script.onload = () => resolve(script);
    script.onerror = () => reject(new Error(`Failed to load ${src}`));
    if (options.integrity) script.integrity = options.integrity;
    if (options.crossOrigin) script.crossOrigin = options.crossOrigin;
    document.head.appendChild(script);
  });
}

// ใช้งาน
loadScript('https://cdn.example.com/lib.js')
  .then(() => console.log('Loaded!'))
  .catch(err => console.error(err));

// 2. Dynamic import (ES Modules) - แนะนำสำหรับ modern apps
async function loadModule() {
  const module = await import('./module.js');
  module.default();
}

เหตุการณ์ (Events)

  • onload - โหลดสำเร็จ
  • onerror - โหลดล้มเหลว
  • onreadystatechange - สำหรับ IE เก่า (readyState: loading, loaded, complete)

Security Best Practices

  • ใช้ integrity (SRI) สำหรับ CDN scripts
  • ใช้ crossorigin="anonymous" ร่วมกับ SRI
  • หลีกเลี่ยง eval() และ new Function() กับ user input
  • Content Security Policy (CSP) header เพื่อจำกัด script sources