偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

談?wù)凧S二進(jìn)制:File、Blob、FileReader、ArrayBuffer、Base64

開(kāi)發(fā) 前端
一些小的圖片都可以使用 base64 格式進(jìn)行展示,img標(biāo)簽和background的 url 屬性都支持使用base64 格式的圖片,這樣做也可以減少 HTTP 請(qǐng)求。

大家好,我是 CUGGZ。

JavaScript 提供了一些 API 來(lái)處理文件或原始文件數(shù)據(jù),例如:File、Blob、FileReader、ArrayBuffer、base64 等。下面就來(lái)看看它們都是如何使用的,它們之間又有何區(qū)別和聯(lián)系!

圖片

1. Blob

Blob 全稱為 binary large object ,即二進(jìn)制大對(duì)象,它是 JavaScript 中的一個(gè)對(duì)象,表示原始的類似文件的數(shù)據(jù)。下面是 MDN 中對(duì) Blob 的解釋:

Blob 對(duì)象表示一個(gè)不可變、原始數(shù)據(jù)的類文件對(duì)象。它的數(shù)據(jù)可以按文本或二進(jìn)制的格式進(jìn)行讀取,也可以轉(zhuǎn)換成 ReadableStream 來(lái)用于數(shù)據(jù)操作。

實(shí)際上,Blob 對(duì)象是包含有只讀原始數(shù)據(jù)的類文件對(duì)象。簡(jiǎn)單來(lái)說(shuō),Blob 對(duì)象就是一個(gè)不可修改的二進(jìn)制文件。

(1)Blob 創(chuàng)建

可以使用 Blob() 構(gòu)造函數(shù)來(lái)創(chuàng)建一個(gè) Blob:

new Blob(array, options);

其有兩個(gè)參數(shù):

  • array:由 ArrayBuffer、ArrayBufferView、Blob、DOMString 等對(duì)象構(gòu)成的,將會(huì)被放進(jìn) Blob;
  • options:可選的 BlobPropertyBag 字典,它可能會(huì)指定如下兩個(gè)屬性
  • type:默認(rèn)值為 "",表示將會(huì)被放入到 blob 中的數(shù)組內(nèi)容的 MIME 類型。
  • endings:默認(rèn)值為"transparent",用于指定包含行結(jié)束符\n的字符串如何被寫(xiě)入,不常用。

常見(jiàn)的 MIME 類型如下:

圖片圖片

下面來(lái)看一個(gè)簡(jiǎn)單的例子:

const blob = new Blob(["Hello World"], {type: "text/plain"});

這里可以成為動(dòng)態(tài)文件創(chuàng)建,其正在創(chuàng)建一個(gè)類似文件的對(duì)象。這個(gè) blob 對(duì)象上有兩個(gè)屬性:

  • size:Blob對(duì)象中所包含數(shù)據(jù)的大?。ㄗ止?jié));
  • type:字符串,認(rèn)為該Blob對(duì)象所包含的 MIME 類型。如果類型未知,則為空字符串。

下面來(lái)看打印結(jié)果:

const blob = new Blob(["Hello World"], {type: "text/plain"});

console.log(blob.size); // 11
console.log(blob.type); // "text/plain"

注意,字符串"Hello World"是 UTF-8 編碼的,因此它的每個(gè)字符占用 1 個(gè)字節(jié)。

到現(xiàn)在,Blob 對(duì)象看起來(lái)似乎我們還是沒(méi)有啥用。那該如何使用 Blob 對(duì)象呢?可以使用 URL.createObjectURL() 方法將將其轉(zhuǎn)化為一個(gè) URL,并在 Iframe 中加載:

<iframe></iframe>

const iframe = document.getElementsByTagName("iframe")[0];

const blob = new Blob(["Hello World"], {type: "text/plain"});

iframe.src = URL.createObjectURL(blob);

(2)Blob 分片

除了使用Blob()構(gòu)造函數(shù)來(lái)創(chuàng)建blob 對(duì)象之外,還可以從 blob 對(duì)象中創(chuàng)建blob,也就是將 blob 對(duì)象切片。Blob 對(duì)象內(nèi)置了 slice() 方法用來(lái)將 blob 對(duì)象分片,其語(yǔ)法如下:

const blob = instanceOfBlob.slice([start [, end [, contentType]]]};

其有三個(gè)參數(shù):

  • start:設(shè)置切片的起點(diǎn),即切片開(kāi)始位置。默認(rèn)值為 0,這意味著切片應(yīng)該從第一個(gè)字節(jié)開(kāi)始;
  • end:設(shè)置切片的結(jié)束點(diǎn),會(huì)對(duì)該位置之前的數(shù)據(jù)進(jìn)行切片。默認(rèn)值為blob.size;
  • contentType:設(shè)置新 blob 的 MIME 類型。如果省略 type,則默認(rèn)為 blob 的原始值。

下面來(lái)看例子:

const iframe = document.getElementsByTagName("iframe")[0];

const blob = new Blob(["Hello World"], {type: "text/plain"});

const subBlob = blob.slice(0, 5);

iframe.src = URL.createObjectURL(subBlob);

此時(shí)頁(yè)面會(huì)顯示"Hello"。

2. File

文件(File)接口提供有關(guān)文件的信息,并允許網(wǎng)頁(yè)中的 JavaScript 訪問(wèn)其內(nèi)容。實(shí)際上,F(xiàn)ile 對(duì)象是特殊類型的 Blob,且可以用在任意的 Blob 類型的 context 中。Blob 的屬性和方法都可以用于 File 對(duì)象。

注意:File 對(duì)象中只存在于瀏覽器環(huán)境中,在 Node.js 環(huán)境中不存在。

在 JavaScript 中,主要有兩種方法來(lái)獲取 File 對(duì)象:

  • <input> 元素上選擇文件后返回的 FileList 對(duì)象;
  • 文件拖放操作生成的 DataTransfer 對(duì)象;

(1)input

首先定義一個(gè)輸入類型為 file 的 input 標(biāo)簽:

<input type="file" id="fileInput" multiple="multiple">

這里給 input 標(biāo)簽添加了三個(gè)屬性:

  • type="file":指定 input 的輸入類型為文件;
  • id="fileInput":指定 input 的唯一 id;
  • multiple="multiple":指定 input 可以同時(shí)上傳多個(gè)文件;

下面來(lái)給 input 標(biāo)簽添加 onchange 事件,當(dāng)選擇文件并上傳之后觸發(fā):

const fileInput = document.getElementById("fileInput");

fileInput.onchange = (e) => {
    console.log(e.target.files);
}

當(dāng)點(diǎn)擊上傳文件時(shí),控制臺(tái)就會(huì)輸出一個(gè) FileList 數(shù)組,這個(gè)數(shù)組的每個(gè)元素都是一個(gè) File 對(duì)象,一個(gè)上傳的文件就對(duì)應(yīng)一個(gè) File 對(duì)象:

圖片圖片

每個(gè) File 對(duì)象都包含文件的一些屬性,這些屬性都繼承自 Blob 對(duì)象:

  • lastModified:引用文件最后修改日期,為自1970年1月1日0:00以來(lái)的毫秒數(shù);
  • lastModifiedDate:引用文件的最后修改日期;
  • name:引用文件的文件名;
  • size:引用文件的文件大??;
  • type:文件的媒體類型(MIME);
  • webkitRelativePath:文件的路徑或 URL。

通常,我們?cè)谏蟼魑募r(shí),可以通過(guò)對(duì)比 size 屬性來(lái)限制文件大小,通過(guò)對(duì)比 type 來(lái)限制上傳文件的格式等。

(2)文件拖放

另一種獲取 File 對(duì)象的方式就是拖放 API,這個(gè) API 很簡(jiǎn)單,就是將瀏覽器之外的文件拖到瀏覽器窗口中,并將它放在一個(gè)成為拖放區(qū)域的特殊區(qū)域中。拖放區(qū)域用于響應(yīng)放置操作并從放置的項(xiàng)目中提取信息。這些是通過(guò) ondrop 和 ondragover 兩個(gè) API 實(shí)現(xiàn)的。

下面來(lái)看一個(gè)簡(jiǎn)單的例子,首先定義一個(gè)拖放區(qū)域:

<div id="drop-zone"></div>

然后給這個(gè)元素添加 ondragover 和 ondrop 事件處理程序:

const dropZone = document.getElementById("drop-zone");

dropZone.ondragover = (e) => {
    e.preventDefault();
}

dropZone.ondrop = (e) => {
    e.preventDefault();
    const files = e.dataTransfer.files;
    console.log(files)
}

注意:這里給兩個(gè) API 都添加了 e.preventDefault(),用來(lái)阻止默認(rèn)事件。它是非常重要的,可以用來(lái)阻止瀏覽器的一些默認(rèn)行為,比如放置文件將顯示在瀏覽器窗口中。

當(dāng)拖放文件到拖放區(qū)域時(shí),控制臺(tái)就會(huì)輸出一個(gè)  FileList 數(shù)組,該數(shù)組的每一個(gè)元素都是一個(gè) File 對(duì)象。這個(gè) FileList 數(shù)組是從事件參數(shù)的 dataTransfer 屬性的 files 獲取的:

圖片圖片

可以看到,這里得到的 File 對(duì)象和通過(guò) input 標(biāo)簽獲得的 File 對(duì)象是完全一樣的。

3. FileReader

FileReader 是一個(gè)異步 API,用于讀取文件并提取其內(nèi)容以供進(jìn)一步使用。FileReader 可以將 Blob 讀取為不同的格式。

注意:FileReader 僅用于以安全的方式從用戶(遠(yuǎn)程)系統(tǒng)讀取文件內(nèi)容,不能用于從文件系統(tǒng)中按路徑名簡(jiǎn)單地讀取文件。

(1)基本使用

可以使用 FileReader 構(gòu)造函數(shù)來(lái)創(chuàng)建一個(gè) FileReader 對(duì)象:

const reader = new FileReader();

這個(gè)對(duì)象常用屬性如下:

  • error:表示在讀取文件時(shí)發(fā)生的錯(cuò)誤;
  • result:文件內(nèi)容。該屬性僅在讀取操作完成后才有效,數(shù)據(jù)的格式取決于使用哪個(gè)方法來(lái)啟動(dòng)讀取操作。
  • readyState:表示FileReader狀態(tài)的數(shù)字。取值如下:

圖片圖片

FileReader 對(duì)象提供了以下方法來(lái)加載文件:

  • readAsArrayBuffer():讀取指定 Blob 中的內(nèi)容,完成之后,result 屬性中保存的將是被讀取文件的 ArrayBuffer 數(shù)據(jù)對(duì)象;
  • FileReader.readAsBinaryString():讀取指定 Blob 中的內(nèi)容,完成之后,result 屬性中將包含所讀取文件的原始二進(jìn)制數(shù)據(jù);
  • FileReader.readAsDataURL():讀取指定 Blob 中的內(nèi)容,完成之后,result 屬性中將包含一個(gè)data: URL 格式的 Base64 字符串以表示所讀取文件的內(nèi)容。
  • FileReader.readAsText():讀取指定 Blob 中的內(nèi)容,完成之后,result 屬性中將包含一個(gè)字符串以表示所讀取的文件內(nèi)容。

可以看到,上面這些方法都接受一個(gè)要讀取的 blob 對(duì)象作為參數(shù),讀取完之后會(huì)將讀取的結(jié)果放入對(duì)象的 result 屬性中。

(2)事件處理

FileReader 對(duì)象常用的事件如下:

  • abort:該事件在讀取操作被中斷時(shí)觸發(fā);
  • error:該事件在讀取操作發(fā)生錯(cuò)誤時(shí)觸發(fā);
  • load:該事件在讀取操作完成時(shí)觸發(fā);
  • progress:該事件在讀取 Blob 時(shí)觸發(fā)。

當(dāng)然,這些方法可以加上前置 on 后在HTML元素上使用,比如onload、onerror、onabort、onprogress。除此之外,由于FileReader對(duì)象繼承自EventTarget,因此還可以使用 addEventListener() 監(jiān)聽(tīng)上述事件。

下面來(lái)看一個(gè)簡(jiǎn)單的例子,首先定義一個(gè) input 輸入框用于上傳文件:

<input type="file" id="fileInput">

接下來(lái)定義 input 標(biāo)簽的 onchange 事件處理函數(shù)和FileReader對(duì)象的onload事件處理函數(shù):

const fileInput = document.getElementById("fileInput");

const reader = new FileReader();

fileInput.onchange = (e) => {
    reader.readAsText(e.target.files[0]);
}

reader.onload = (e) => {
    console.log(e.target.result);
}

這里,首先創(chuàng)建了一個(gè) FileReader 對(duì)象,當(dāng)文件上傳成功時(shí),使用 readAsText() 方法讀取 File 對(duì)象,當(dāng)讀取操作完成時(shí)打印讀取結(jié)果。

使用上述例子讀取文本文件時(shí),就是比較正常的。如果讀取二進(jìn)制文件,比如png格式的圖片,往往會(huì)產(chǎn)生亂碼,如下:

圖片圖片

那該如何處理這種二進(jìn)制數(shù)據(jù)呢?readAsDataURL() 是一個(gè)不錯(cuò)的選擇,它可以將讀取的文件的內(nèi)容轉(zhuǎn)換為 base64 數(shù)據(jù)的 URL 表示。這樣,就可以直接將 URL 用在需要源鏈接的地方,比如 img 標(biāo)簽的 src 屬性。

對(duì)于上述例子,將 readAsText 方法改為 readAsDataURL():

const fileInput = document.getElementById("fileInput");

const reader = new FileReader();

fileInput.onchange = (e) => {
    reader.readAsDataURL(e.target.files[0]);
}

reader.onload = (e) => {
    console.log(e.target.result);
}

這時(shí),再次上傳二進(jìn)制圖片時(shí),就會(huì)在控制臺(tái)打印一個(gè) base64 編碼的 URL,如下:

圖片圖片

下面來(lái)修改一下這個(gè)例子,將上傳的圖片通過(guò)以上方式顯示在頁(yè)面上:

<input type="file" id="fileInput" />

<img id="preview" />
const fileInput = document.getElementById("fileInput");
const preview = document.getElementById("preview");
const reader = new FileReader();

fileInput.onchange = (e) => {
  reader.readAsDataURL(e.target.files[0]);
};

reader.onload = (e) => {
  preview.src = e.target.result;
  console.log(e.target.result);
};

圖片圖片

當(dāng)上傳大文件時(shí),可以通過(guò) progress 事件來(lái)監(jiān)控文件的讀取進(jìn)度:

const reader = new FileReader();

reader.onprogress = (e) => {
  if (e.loaded && e.total) {
    const percent = (event.loaded / event.total) * 100;
    console.log(`上傳進(jìn)度: ${Math.round(percent)} %`);
  }
});

progress 事件提供了兩個(gè)屬性:loaded(已讀取量)和total(需讀取總量)。

4. ArrayBuffer

(1)ArrayBuffer

ArrayBuffer 對(duì)象用來(lái)表示通用的、固定長(zhǎng)度的原始二進(jìn)制數(shù)據(jù)緩沖區(qū)。ArrayBuffer 的內(nèi)容不能直接操作,只能通過(guò) DataView 對(duì)象或 TypedArrray 對(duì)象來(lái)訪問(wèn)。這些對(duì)象用于讀取和寫(xiě)入緩沖區(qū)內(nèi)容。

ArrayBuffer 本身就是一個(gè)黑盒,不能直接讀寫(xiě)所存儲(chǔ)的數(shù)據(jù),需要借助以下視圖對(duì)象來(lái)讀寫(xiě):

  • TypedArray:用來(lái)生成內(nèi)存的視圖,通過(guò)9個(gè)構(gòu)造函數(shù),可以生成9種數(shù)據(jù)格式的視圖。
  • DataViews:用來(lái)生成內(nèi)存的視圖,可以自定義格式和字節(jié)序。

圖片圖片

TypedArray視圖和 DataView視圖的區(qū)別主要是字節(jié)序,前者的數(shù)組成員都是同一個(gè)數(shù)據(jù)類型,后者的數(shù)組成員可以是不同的數(shù)據(jù)類型。

那 ArrayBuffer 與 Blob 有啥區(qū)別呢?根據(jù) ArrayBuffer 和 Blob 的特性,Blob 作為一個(gè)整體文件,適合用于傳輸;當(dāng)需要對(duì)二進(jìn)制數(shù)據(jù)進(jìn)行操作時(shí)(比如要修改某一段數(shù)據(jù)時(shí)),就可以使用 ArrayBuffer。

下面來(lái)看看 ArrayBuffer 有哪些常用的方法和屬性。

① new ArrayBuffer()

ArrayBuffer 可以通過(guò)以下方式生成:

new ArrayBuffer(bytelength)

ArrayBuffer()構(gòu)造函數(shù)可以分配指定字節(jié)數(shù)量的緩沖區(qū),其參數(shù)和返回值如下:

  • 參數(shù):它接受一個(gè)參數(shù),即 bytelength,表示要?jiǎng)?chuàng)建數(shù)組緩沖區(qū)的大?。ㄒ宰止?jié)為單位。);
  • 返回值:返回一個(gè)新的指定大小的ArrayBuffer對(duì)象,內(nèi)容初始化為0。

② ArrayBuffer.prototype.byteLength

ArrayBuffer 實(shí)例上有一個(gè) byteLength 屬性,它是一個(gè)只讀屬性,表示 ArrayBuffer 的 byte 的大小,在 ArrayBuffer 構(gòu)造完成時(shí)生成,不可改變。來(lái)看例子:

const buffer = new ArrayBuffer(16); 
console.log(buffer.byteLength);  // 16

③ ArrayBuffer.prototype.slice()

ArrayBuffer 實(shí)例上還有一個(gè) slice 方法,該方法可以用來(lái)截取 ArrayBuffer 實(shí)例,它返回一個(gè)新的 ArrayBuffer ,它的內(nèi)容是這個(gè) ArrayBuffer 的字節(jié)副本,從 begin(包括),到 end(不包括)。來(lái)看例子:

const buffer = new ArrayBuffer(16); 
console.log(buffer.slice(0, 8));  // 16

這里會(huì)從 buffer 對(duì)象上將前8個(gè)字節(jié)生成一個(gè)新的ArrayBuffer對(duì)象。這個(gè)方法實(shí)際上有兩步操作,首先會(huì)分配一段指定長(zhǎng)度的內(nèi)存,然后拷貝原來(lái)ArrayBuffer對(duì)象的置頂部分。

④ ArrayBuffer.isView()

ArrayBuffer 上有一個(gè) isView()方法,它的返回值是一個(gè)布爾值,如果參數(shù)是 ArrayBuffer 的視圖實(shí)例則返回 true,例如類型數(shù)組對(duì)象或 DataView 對(duì)象;否則返回 false。簡(jiǎn)單來(lái)說(shuō),這個(gè)方法就是用來(lái)判斷參數(shù)是否是 TypedArray 實(shí)例或者 DataView 實(shí)例:

const buffer = new ArrayBuffer(16);
ArrayBuffer.isView(buffer)   // false

const view = new Uint32Array(buffer);
ArrayBuffer.isView(view)     // true

(2)TypedArray

TypedArray 對(duì)象一共提供 9 種類型的視圖,每一種視圖都是一種構(gòu)造函數(shù)。如下:

元素

類型化數(shù)組

字節(jié)

描述

Int8

Int8Array

1

8 位有符號(hào)整數(shù)

Uint8

Uint8Array

1

8 位無(wú)符號(hào)整數(shù)

Uint8C

Uint8ClampedArray

1

8 位無(wú)符號(hào)整數(shù)

Int16

Int16Array

2

16 位有符號(hào)整數(shù)

Uint16

Uint16Array

2

16 位無(wú)符號(hào)整數(shù)

Int32

Int32Array

4

32 位有符號(hào)整數(shù)

Uint32

Uint32Array

4

32 位無(wú)符號(hào)整數(shù)

Float32

Float32Array

4

32 位浮點(diǎn)

Float64

Float64Array

8

64 位浮點(diǎn)

來(lái)看看這些都是什么意思:

  • Uint8Array: 將 ArrayBuffer 中的每個(gè)字節(jié)視為一個(gè)整數(shù),可能的值從 0 到 255 (一個(gè)字節(jié)等于 8 位)。這樣的值稱為“8 位無(wú)符號(hào)整數(shù)”。
  • Uint16Array:將 ArrayBuffer 中任意兩個(gè)字節(jié)視為一個(gè)整數(shù),可能的值從 0 到 65535。這樣的值稱為“16 位無(wú)符號(hào)整數(shù)”。
  • Uint32Array:將 ArrayBuffer 中任何四個(gè)字節(jié)視為一個(gè)整數(shù),可能值從 0 到 4294967295,這樣的值稱為“32 位無(wú)符號(hào)整數(shù)”。

這些構(gòu)造函數(shù)生成的對(duì)象統(tǒng)稱為 TypedArray 對(duì)象。它們和正常的數(shù)組很類似,都有l(wèi)ength 屬性,都能用索引獲取數(shù)組元素,所有數(shù)組的方法都可以在類型化數(shù)組上面使用。

那類型化數(shù)組和數(shù)組有什么區(qū)別呢?

  • 類型化數(shù)組的元素都是連續(xù)的,不會(huì)為空;
  • 類型化數(shù)組的所有成員的類型和格式相同;
  • 類型化數(shù)組元素默認(rèn)值為 0;
  • 類型化數(shù)組本質(zhì)上只是一個(gè)視圖層,不會(huì)存儲(chǔ)數(shù)據(jù),數(shù)據(jù)都存儲(chǔ)在更底層的 ArrayBuffer 對(duì)象中。

下面來(lái)看看 TypedArray 都有哪些常用的方法和屬性。

① new TypedArray()

TypedArray 的語(yǔ)法如下(TypedArray只是一個(gè)概念,實(shí)際使用的是那9個(gè)對(duì)象):

new Int8Array(length);
new Int8Array(typedArray);
new Int8Array(object);
new Int8Array(buffer [, byteOffset [, length]]);

可以看到,TypedArray 有多種用法,下面來(lái)分別看一下。

  • TypedArray(length) :通過(guò)分配指定長(zhǎng)度內(nèi)容進(jìn)行分配
let view = new Int8Array(16);
view[0] = 10;
view[10] = 6;
console.log(view);

輸出結(jié)果如下:

圖片圖片

這里就生成了一個(gè) 16個(gè)元素的 Int8Array 數(shù)組,除了手動(dòng)賦值的元素,其他元素的初始值都是 0。

  • TypedArray(typeArray) :接收一個(gè)視圖實(shí)例作為參數(shù)
const view = new Int8Array(new Uint8Array(6));
view[0] = 10;
view[3] = 6;
console.log(view);

輸出結(jié)果如下:

圖片圖片

  • TypedArray(object) :參數(shù)可以是一個(gè)普通數(shù)組
const view = new Int8Array([1, 2, 3, 4, 5]);
view[0] = 10;
view[3] = 6;
console.log(view);

輸出結(jié)果如下:

圖片圖片

需要注意,TypedArray視圖會(huì)開(kāi)辟一段新的內(nèi)存,不會(huì)在原數(shù)組上建立內(nèi)存。當(dāng)然,這里創(chuàng)建的類型化數(shù)組也能轉(zhuǎn)換回普通數(shù)組:

Array.prototype.slice.call(view); // [10, 2, 3, 6, 5]
  • TypeArray(buffer [, byteOffset [, length]]) :

這種方式有三個(gè)參數(shù),其中第一個(gè)參數(shù)是一個(gè)ArrayBuffer對(duì)象;第二個(gè)參數(shù)是視圖開(kāi)始的字節(jié)序號(hào),默認(rèn)從0開(kāi)始,可選;第三個(gè)參數(shù)是視圖包含的數(shù)據(jù)個(gè)數(shù),默認(rèn)直到本段內(nèi)存區(qū)域結(jié)束。

const buffer = new ArrayBuffer(8);
const view1 = new Int32Array(buffer); 
const view2 = new Int32Array(buffer, 4); 
console.log(view1, view2);

輸出結(jié)果如下:

圖片圖片

② BYTES_PER_ELEMENT

每種視圖的構(gòu)造函數(shù)都有一個(gè) BYTES_PER_ELEMENT 屬性,表示這種數(shù)據(jù)類型占據(jù)的字節(jié)數(shù):

Int8Array.BYTES_PER_ELEMENT // 1
Uint8Array.BYTES_PER_ELEMENT // 1
Int16Array.BYTES_PER_ELEMENT // 2
Uint16Array.BYTES_PER_ELEMENT // 2
Int32Array.BYTES_PER_ELEMENT // 4
Uint32Array.BYTES_PER_ELEMENT // 4
Float32Array.BYTES_PER_ELEMENT // 4
Float64Array.BYTES_PER_ELEMENT // 8

BYTES_PER_ELEMENT 屬性也可以在類型化數(shù)組的實(shí)例上獲?。?/p>

const buffer = new ArrayBuffer(16); 
const view = new Uint32Array(buffer); 
console.log(Uint32Array.BYTES_PER_ELEMENT); // 4

③ TypedArray.prototype.buffer

TypedArray 實(shí)例的 buffer 屬性會(huì)返回內(nèi)存中對(duì)應(yīng)的 ArrayBuffer對(duì)象,只讀屬性。

const a = new Uint32Array(8);
const b = new Int32Array(a.buffer); 
console.log(a, b);

輸出結(jié)果如下:

圖片圖片

④ TypedArray.prototype.slice()

TypeArray 實(shí)例的 slice方法可以返回一個(gè)指定位置的新的 TypedArray實(shí)例。

const view = new Int16Array(8);
console.log(view.slice(0 ,5));

輸出結(jié)果如下:

圖片圖片

⑤ byteLength 和 length

  • byteLength:返回 TypedArray 占據(jù)的內(nèi)存長(zhǎng)度,單位為字節(jié);
  • length:返回 TypedArray 元素個(gè)數(shù);
const view = new Int16Array(8);
view.length;      // 8
view.byteLength;  // 16

(3)DataView

說(shuō)完 ArrayBuffer,下面來(lái)看看另一種操作 ArrayBuffer 的方式:DataView。DataView 視圖是一個(gè)可以從 二進(jìn)制 ArrayBuffer 對(duì)象中讀寫(xiě)多種數(shù)值類型的底層接口,使用它時(shí),不用考慮不同平臺(tái)的字節(jié)序問(wèn)題。

DataView視圖提供更多操作選項(xiàng),而且支持設(shè)定字節(jié)序。本來(lái),在設(shè)計(jì)目的上,ArrayBuffer對(duì)象的各種TypedArray視圖,是用來(lái)向網(wǎng)卡、聲卡之類的本機(jī)設(shè)備傳送數(shù)據(jù),所以使用本機(jī)的字節(jié)序就可以了;而DataView視圖的設(shè)計(jì)目的,是用來(lái)處理網(wǎng)絡(luò)設(shè)備傳來(lái)的數(shù)據(jù),所以大端字節(jié)序或小端字節(jié)序是可以自行設(shè)定的。

① new DataView()

DataView視圖可以通過(guò)構(gòu)造函數(shù)來(lái)創(chuàng)建,它的參數(shù)是一個(gè)ArrayBuffer對(duì)象,生成視圖。其語(yǔ)法如下:

new DataView(buffer [, byteOffset [, byteLength]])

其有三個(gè)參數(shù):

  • buffer:一個(gè)已經(jīng)存在的 ArrayBuffer 對(duì)象,DataView 對(duì)象的數(shù)據(jù)源。
  • byteOffset:可選,此 DataView 對(duì)象的第一個(gè)字節(jié)在 buffer 中的字節(jié)偏移。如果未指定,則默認(rèn)從第一個(gè)字節(jié)開(kāi)始。
  • byteLength:可選,此 DataView 對(duì)象的字節(jié)長(zhǎng)度。如果未指定,這個(gè)視圖的長(zhǎng)度將匹配 buffer 的長(zhǎng)度。

來(lái)看一個(gè)例子:

const buffer = new ArrayBuffer(16);
const view = new DataView(buffer);
console.log(view);

打印結(jié)果如下:

圖片圖片

② buffer、byteLength、byteOffset

DataView 實(shí)例有以下常用屬性:

  • buffer:返回對(duì)應(yīng)的ArrayBuffer對(duì)象;
  • byteLength:返回占據(jù)的內(nèi)存字節(jié)長(zhǎng)度;
  • byteOffset:返回當(dāng)前視圖從對(duì)應(yīng)的ArrayBuffer對(duì)象的哪個(gè)字節(jié)開(kāi)始。
const buffer = new ArrayBuffer(16);
const view = new DataView(buffer);
view.buffer;
view.byteLength;
view.byteOffset;

打印結(jié)果如下:

圖片圖片

③ 讀取內(nèi)存

DataView 實(shí)例提供了以下方法來(lái)讀取內(nèi)存,它們的參數(shù)都是一個(gè)字節(jié)序號(hào),表示開(kāi)始讀取的字節(jié)位置:

  • getInt8:讀取1個(gè)字節(jié),返回一個(gè)8位整數(shù)。
  • getUint8:讀取1個(gè)字節(jié),返回一個(gè)無(wú)符號(hào)的8位整數(shù)。
  • getInt16:讀取2個(gè)字節(jié),返回一個(gè)16位整數(shù)。
  • getUint16:讀取2個(gè)字節(jié),返回一個(gè)無(wú)符號(hào)的16位整數(shù)。
  • getInt32:讀取4個(gè)字節(jié),返回一個(gè)32位整數(shù)。
  • getUint32:讀取4個(gè)字節(jié),返回一個(gè)無(wú)符號(hào)的32位整數(shù)。
  • getFloat32:讀取4個(gè)字節(jié),返回一個(gè)32位浮點(diǎn)數(shù)。
  • getFloat64:讀取8個(gè)字節(jié),返回一個(gè)64位浮點(diǎn)數(shù)。

下面來(lái)看一個(gè)例子:

const buffer = new ArrayBuffer(24);
const view = new DataView(buffer);

// 從第1個(gè)字節(jié)讀取一個(gè)8位無(wú)符號(hào)整數(shù)
const view1 = view.getUint8(0);

// 從第2個(gè)字節(jié)讀取一個(gè)16位無(wú)符號(hào)整數(shù)
const view2 = view.getUint16(1);

// 從第4個(gè)字節(jié)讀取一個(gè)16位無(wú)符號(hào)整數(shù)
const view3 = view.getUint16(3);

④ 寫(xiě)入內(nèi)存

DataView 實(shí)例提供了以下方法來(lái)寫(xiě)入內(nèi)存,它們都接受兩個(gè)參數(shù),第一個(gè)參數(shù)表示開(kāi)始寫(xiě)入數(shù)據(jù)的字節(jié)序號(hào),第二個(gè)參數(shù)為寫(xiě)入的數(shù)據(jù):

  • setInt8:寫(xiě)入1個(gè)字節(jié)的8位整數(shù)。
  • setUint8:寫(xiě)入1個(gè)字節(jié)的8位無(wú)符號(hào)整數(shù)。
  • setInt16:寫(xiě)入2個(gè)字節(jié)的16位整數(shù)。
  • setUint16:寫(xiě)入2個(gè)字節(jié)的16位無(wú)符號(hào)整數(shù)。
  • setInt32:寫(xiě)入4個(gè)字節(jié)的32位整數(shù)。
  • setUint32:寫(xiě)入4個(gè)字節(jié)的32位無(wú)符號(hào)整數(shù)。
  • setFloat32:寫(xiě)入4個(gè)字節(jié)的32位浮點(diǎn)數(shù)。
  • setFloat64:寫(xiě)入8個(gè)字節(jié)的64位浮點(diǎn)數(shù)。

5. Object URL

Object URL(MDN定義名稱)又稱Blob URL(W3C定義名稱),是HTML5中的新標(biāo)準(zhǔn)。它是一個(gè)用來(lái)表示File Object 或Blob Object 的URL。在網(wǎng)頁(yè)中,我們可能會(huì)看到過(guò)這種形式的 Blob URL:

圖片圖片

其實(shí) Blob URL/Object URL 是一種偽協(xié)議,允許將 Blob 和 File 對(duì)象用作圖像、二進(jìn)制數(shù)據(jù)下載鏈接等的 URL 源。

對(duì)于 Blob/File 對(duì)象,可以使用 URL構(gòu)造函數(shù)的 createObjectURL() 方法創(chuàng)建將給出的對(duì)象的 URL。這個(gè) URL 對(duì)象表示指定的 File 對(duì)象或 Blob 對(duì)象。我們可以在<img>、<script> 標(biāo)簽中或者 <a> 和 <link> 標(biāo)簽的 href 屬性中使用這個(gè) URL。

來(lái)看一個(gè)簡(jiǎn)單的例子,首先定義一個(gè)文件上傳的 input 和一個(gè) 圖片預(yù)覽的 img:

<input type="file" id="fileInput" />

<img id="preview" />

再來(lái)使用 URL.createObjectURL() 將File 對(duì)象轉(zhuǎn)化為一個(gè) URL:

const fileInput = document.getElementById("fileInput");
const preview = document.getElementById("preview");

fileInput.onchange = (e) => {
  preview.src = URL.createObjectURL(e.target.files[0]);
  console.log(preview.src);
};

可以看到,上傳的圖片轉(zhuǎn)化成了一個(gè) URL,并顯示在了屏幕上:

圖片圖片

那這個(gè) API 有什么意義呢?可以將Blob/File對(duì)象轉(zhuǎn)化為URL,通過(guò)這個(gè)URL 就可以實(shí)現(xiàn)文件下載或者圖片顯示等。

當(dāng)我們使用createObjectURL()方法創(chuàng)建一個(gè)data URL 時(shí),就需要使用revokeObjectURL()方法從內(nèi)存中清除它來(lái)釋放內(nèi)存。雖然瀏覽器會(huì)在文檔卸載時(shí)自動(dòng)釋放 Data URL,但為了提高性能,我們應(yīng)該使用revokeObjectURL()來(lái)手動(dòng)釋放它。revokeObjectURL()方法接受一個(gè)Data URL 作為其參數(shù),返回undefined。下面來(lái)看一個(gè)例子:

const objUrl = URL.createObjectURL(new File([""], "filename"));
console.log(objUrl);
URL.revokeObjectURL(objUrl);

6. Base64

Base64 是一種基于64個(gè)可打印字符來(lái)表示二進(jìn)制數(shù)據(jù)的表示方法。Base64 編碼普遍應(yīng)用于需要通過(guò)被設(shè)計(jì)為處理文本數(shù)據(jù)的媒介上儲(chǔ)存和傳輸二進(jìn)制數(shù)據(jù)而需要編碼該二進(jìn)制數(shù)據(jù)的場(chǎng)景。這樣是為了保證數(shù)據(jù)的完整并且不用在傳輸過(guò)程中修改這些數(shù)據(jù)。

在 JavaScript 中,有兩個(gè)函數(shù)被分別用來(lái)處理解碼和編碼 base64 字符串:

  • atob():解碼,解碼一個(gè) Base64 字符串;
  • btoa():編碼,從一個(gè)字符串或者二進(jìn)制數(shù)據(jù)編碼一個(gè) Base64 字符串。
btoa("JavaScript")       // 'SmF2YVNjcmlwdA=='
atob('SmF2YVNjcmlwdA==') // 'JavaScript'

那 base64 的實(shí)際應(yīng)用場(chǎng)景有哪些呢?其實(shí)多數(shù)場(chǎng)景就是基于Data URL的。比如,使用toDataURL()方法把 canvas 畫(huà)布內(nèi)容生成 base64 編碼格式的圖片:

const canvas = document.getElementById('canvas'); 
const ctx = canvas.getContext("2d");
const dataUrl = canvas.toDataURL();

除此之外,還可以使用readAsDataURL()方法把上傳的文件轉(zhuǎn)為base64格式的data URI,比如上傳頭像展示或者編輯:

<input type="file" id="fileInput" />

<img id="preview" />
const fileInput = document.getElementById("fileInput");
const preview = document.getElementById("preview");
const reader = new FileReader();

fileInput.onchange = (e) => {
  reader.readAsDataURL(e.target.files[0]);
};

reader.onload = (e) => {
  preview.src = e.target.result;
  console.log(e.target.result);
};

效果如下,將圖片(二進(jìn)制數(shù)據(jù))轉(zhuǎn)化為可打印的字符,也便于數(shù)據(jù)的傳輸:

圖片圖片

另外,一些小的圖片都可以使用 base64 格式進(jìn)行展示,img標(biāo)簽和background的 url 屬性都支持使用base64 格式的圖片,這樣做也可以減少 HTTP 請(qǐng)求。

7. 格式轉(zhuǎn)化

看完這些基本的概念,下面就來(lái)看看常用格式之間是如何轉(zhuǎn)換的。

(1)ArrayBuffer → blob

const blob = new Blob([new Uint8Array(buffer, byteOffset, length)]);

(2)ArrayBuffer → base64

const base64 = btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)));

(3)base64 → blob

const base64toBlob = (base64Data, contentType, sliceSize) => {
  const byteCharacters = atob(base64Data);
  const byteArrays = [];

  for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
    const slice = byteCharacters.slice(offset, offset + sliceSize);

    const byteNumbers = new Array(slice.length);
    for (let i = 0; i < slice.length; i++) {
      byteNumbers[i] = slice.charCodeAt(i);
    }

    const byteArray = new Uint8Array(byteNumbers);
    byteArrays.push(byteArray);
  }

  const blob = new Blob(byteArrays, {type: contentType});
  return blob;
}

(4)blob → ArrayBuffer

function blobToArrayBuffer(blob) { 
  return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = () => resolve(reader.result);
      reader.onerror = () => reject;
      reader.readAsArrayBuffer(blob);
  });
}

(5)blob → base64

function blobToBase64(blob) {
  return new Promise((resolve) => {
    const reader = new FileReader();
    reader.onloadend = () => resolve(reader.result);
    reader.readAsDataURL(blob);
  });
}

(6)blob → Object URL

const objectUrl = URL.createObjectURL(blob);
責(zé)任編輯:武曉燕 來(lái)源: 前端充電寶
相關(guān)推薦

2022-09-28 08:01:33

JavaScript二進(jìn)制

2025-04-23 00:04:00

2017-04-11 10:48:53

JS二進(jìn)制

2023-11-07 08:35:26

2020-06-15 17:05:46

前端二進(jìn)制瀏覽器

2009-02-27 09:37:33

Google二進(jìn)制代碼

2018-10-22 14:37:16

二進(jìn)制數(shù)據(jù)存儲(chǔ)

2022-10-31 08:02:42

二進(jìn)制計(jì)算乘法

2016-12-13 13:50:06

JAVA轉(zhuǎn)換Base64

2021-02-05 05:26:33

字節(jié)ASCII控制

2025-02-11 00:00:10

Base64編碼二進(jìn)制

2010-06-09 13:02:29

MySQL啟用二進(jìn)制日

2010-10-13 15:45:23

MySQL二進(jìn)制日志

2009-08-12 18:06:53

C#讀取二進(jìn)制文件

2009-12-16 10:49:42

Ruby操作二進(jìn)制文件

2022-07-26 13:00:01

安全符號(hào)源代碼

2014-02-20 10:28:28

JavaScriptBase64

2024-03-13 14:57:37

2022-07-18 09:01:15

SwiftApple二進(jìn)制目標(biāo)

2024-01-31 09:55:53

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)