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

JavaScript ArrayBuffer.byteLength Property - ขนาดของ ArrayBuffer


ArrayBuffer.prototype.byteLength คืออะไร?

byteLength เป็น read-only property ของ ArrayBuffer ที่คืนค่าขนาดของ buffer ในหน่วย Bytes (ไบต์) กำหนดตอนสร้างและไม่สามารถเปลี่ยนแปลงได้

ตัวอย่างโค้ดครบถ้วน

<!DOCTYPE html>
<html lang="th">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>ArrayBuffer.byteLength</title>
  <style>
    body { font-family: 'Segoe UI', sans-serif; padding: 20px; max-width: 800px; margin: 0 auto; }
    .panel { background: #f5f5f5; padding: 20px; border-radius: 8px; margin-bottom: 20px; }
    .code { background: #2d2d2d; color: #f8f8f2; padding: 15px; border-radius: 4px; font-family: monospace; overflow-x: auto; }
    .output { background: #e8f5e9; padding: 15px; border-radius: 4px; font-family: monospace; white-space: pre-wrap; }
    button { padding: 10px 20px; background: #7e32d4; color: white; border: none; border-radius: 4px; cursor: pointer; margin-right: 10px; margin-bottom: 10px; }
    button:hover { background: #6a1b9a; }
    table { width: 100%; border-collapse: collapse; margin-top: 10px; }
    th, td { padding: 10px; border: 1px solid #ddd; text-align: left; }
    th { background: #7e32d4; color: white; }
    .view-info { background: white; padding: 15px; border-radius: 4px; margin: 10px 0; border-left: 4px solid #7e32d4; }
  </style>
</head>
<body>
  <h1>ArrayBuffer.prototype.byteLength</h1>
  <p>คุณสมบัติอ่านอย่างเดียวที่คืนขนาดของ Array Buffer ในหน่วย Bytes</p>
  
  <div class="panel">
    <h3>ทดสอบขนาด Buffer ต่างๆ</h3>
    <button onclick="demoBasic()">Basic Sizes</button>
    <button onclick="demoViews()">Views & Offsets</button>
    <button onclick="demoResize()">Resize (Transfer)</button>
  </div>
  
  <div class="panel">
    <h3>ผลลัพธ์</h3>
    <div class="output" id="output"></div>
  </div>

  <script>
    const output = document.getElementById('output');
    
    function log(msg) {
      output.textContent += msg + '\n';
    }
    
    function clear() { output.textContent = ''; }
    
    function demoBasic() {
      clear();
      log('=== ArrayBuffer byteLength ===\n');
      
      const sizes = [0, 1, 8, 16, 64, 1024, 1024 * 1024]; // 0, 1B, 8B, 16B, 64B, 1KB, 1MB
      
      sizes.forEach(size => {
        const buffer = new ArrayBuffer(size);
        log(`new ArrayBuffer(${size}) → byteLength: ${buffer.byteLength} bytes (${formatBytes(buffer.byteLength)})`);
      });
      
      log('\n--- Max Size ---');
      try {
        const maxBuffer = new ArrayBuffer(Number.MAX_SAFE_INTEGER);
        log(`Max safe: ${maxBuffer.byteLength} bytes`);
      } catch (e) {
        log(`Max size limited by engine: ${e.message}`);
      }
    }
    
    function demoViews() {
      clear();
      log('=== Views share buffer.byteLength ===\n');
      
      const buffer = new ArrayBuffer(32); // 32 bytes
      log(`Original Buffer: ${buffer.byteLength} bytes\n`);
      
      const views = [
        { name: 'Int8Array (1 byte each)', view: new Int8Array(buffer) },
        { name: 'Uint16Array (2 bytes each)', view: new Uint16Array(buffer) },
        { name: 'Int32Array (4 bytes each)', view: new Int32Array(buffer) },
        { name: 'Float64Array (8 bytes each)', view: new Float64Array(buffer) },
        { name: 'DataView', view: new DataView(buffer) }
      ];
      
      views.forEach(({ name, view }) => {
        log(`${name}:`);
        log(`  view.byteLength = ${view.byteLength} bytes`);
        log(`  view.byteOffset = ${view.byteOffset}`);
        log(`  view.buffer.byteLength = ${view.buffer.byteLength} bytes`);
        log(`  Elements: ${view.byteLength / (view.BYTES_PER_ELEMENT || 1)}`);
        log('');
      });
      
      // View with offset
      log('--- View with Offset ---');
      const offsetView = new Int32Array(buffer, 8, 4); // เริ่มที่ byte 8, ยาว 4 elements (16 bytes)
      log(`new Int32Array(buffer, 8, 4):`);
      log(`  byteLength: ${offsetView.byteLength} (4 elements × 4 bytes)`);
      log(`  byteOffset: ${offsetView.byteOffset}`);
      log(`  buffer.byteLength: ${offsetView.buffer.byteLength} (unchanged)`);
    }
    
    function demoResize() {
      clear();
      log('=== Resizing ArrayBuffer (Resizable - ES2024) ===\n');
      
      // Standard ArrayBuffer - ไม่ resize ได้
      const fixedBuffer = new ArrayBuffer(100);
      log(`Fixed buffer: ${fixedBuffer.byteLength} bytes`);
      log('Cannot resize fixed ArrayBuffer\n');
      
      // Resizable ArrayBuffer (ES2024 / Stage 3)
      if (typeof ArrayBuffer.prototype.resize === 'function') {
        const resizable = new ArrayBuffer(100, { maxByteLength: 1000 });
        log(`Resizable buffer: ${resizable.byteLength} / max ${resizable.maxByteLength} bytes`);
        log(`resizable.resize(200) → `);
        resizable.resize(200);
        log(`  New byteLength: ${resizable.byteLength}`);
        log(`resizable.resize(50) → `);
        resizable.resize(50);
        log(`  New byteLength: ${resizable.byteLength}`);
      } else {
        log('Resizable ArrayBuffer not supported in this environment');
        log('Polyfill: ใช้ ArrayBuffer.transfer() หรือสร้างใหม่ + copy');
      }
    }
    
    function formatBytes(bytes) {
      if (bytes === 0) return '0 B';
      const k = 1024;
      const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
      const i = Math.floor(Math.log(bytes) / Math.log(k));
      return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`;
    }
    
    demoBasic();
  </script>
</body>
</html>

ความสัมพันธ์ระหว่าง Buffer และ Views

const buffer = new ArrayBuffer(16);  // 16 bytes

// Views ต่างๆ มอง buffer เดียวกัน แต่ byteLength ต่างกัน
new Int8Array(buffer).byteLength    // 16  (16 elements × 1 byte)
new Int16Array(buffer).byteLength   // 16  (8 elements × 2 bytes)
new Int32Array(buffer).byteLength   // 16  (4 elements × 4 bytes)
new Float64Array(buffer).byteLength // 16  (2 elements × 8 bytes)
new DataView(buffer).byteLength     // 16  (full buffer)

// View with offset/length
new Int32Array(buffer, 4, 2).byteLength  // 8  (2 elements × 4 bytes, เริ่มที่ byte 4)
new DataView(buffer, 8).byteLength       // 8  (จาก byte 8 ถึงสิ้นสุด)

ArrayBuffer vs View byteLength

PropertyArrayBufferTypedArray / DataView
byteLengthขนาด buffer ทั้งหมด (fixed)ขนาดของ view นี้ (อาจน้อยกว่า buffer)
byteOffsetN/Aตำแหน่งเริ่มต้นใน buffer (bytes)
bufferN/Aอ้างอิง ArrayBuffer ต้นทาง
Mutableไม่ (standard) / ใช่ (resizable)ข้อมูล mutable, แต่ view metadata immutable

Resizable ArrayBuffer (ES2024 / Stage 3)

// สร้าง resizable buffer
const buffer = new ArrayBuffer(100, { maxByteLength: 1000 });
console.log(buffer.byteLength);     // 100
console.log(buffer.maxByteLength);  // 1000
console.log(buffer.resizable);      // true

// ขยาย
buffer.resize(500);
console.log(buffer.byteLength);     // 500

// หด
buffer.resize(50);
console.log(buffer.byteLength);     // 50

// ไม่สามารถเกิน maxByteLength
buffer.resize(2000); // RangeError

การประยุกต์ใช้จริง

1. ตรวจสอบขนาดก่อนอ่าน/เขียน

function readInt32(view, offset) {
  if (offset + 4 > view.byteLength) {
    throw new RangeError(`Offset ${offset} out of bounds (length: ${view.byteLength})`);
  }
  return new DataView(view.buffer, view.byteOffset + offset).getInt32(0);
}

2. คำนวณจำนวน Elements

function getElementCount(view) {
  return view.byteLength / view.BYTES_PER_ELEMENT;
}

const arr = new Float32Array(100);
console.log(getElementCount(arr)); // 100

3. Memory Monitoring

function getMemoryUsage(buffers) {
  return buffers.reduce((sum, buf) => sum + buf.byteLength, 0);
}

const buffers = [new ArrayBuffer(1024), new ArrayBuffer(2048)];
console.log(`Total: ${getMemoryUsage(buffers)} bytes`); // 3072

Browser Support

  • byteLength: ทุกเบราว์เซอร์รองรับ (IE10+)
  • resizable ArrayBuffer: Chrome 122+, Firefox 127+, Safari 17.4+ (ES2024)
  • ArrayBuffer.transfer(): Chrome 113+ (Transferable, zero-copy)