相关文章推荐
爱看书的竹笋  ·  3.10 ...·  昨天    · 
千杯不醉的豆腐  ·  Butterworth ...·  3 月前    · 
曾深爱过的消炎药  ·  PHP curl ...·  3 月前    · 
腼腆的皮带  ·  jupyter ...·  1 年前    · 
腼腆的土豆  ·  Delphi ...·  1 年前    · 
类型化数组是JavaScript操作二进制数据的一个接口。 这要从WebGL项目的诞生说起,所谓WebGL,就是指浏览器与显卡之间的通信接口,为了满足JavaScript与显卡之间大量的、实时的数据交换,它们之间的数据通信必须是二进制的,而不能是传统的文本格式。 比如,以文本格式传递一个32位整数,两端的JavaScript脚本与显卡都要进行格式转化,将非常耗时。这时要是存在一种机制,可以像C语言那样,直接操作字节,然后将4个字节的32位整数,以二进制形式原封不动地送入显卡,脚本的性能就会大幅提升。 类型化数组(Typed Array)就是在这种背景下诞生的。它很像C语言的数组,允许开发者以数组下标的形式,直接操作内存。有了类型化数组以后,JavaScript的二进制数据处理功能增强了很多,接口之间完全可以用二进制数据通信。 ## 分配内存 类型化数组是建立在ArrayBuffer对象的基础上的。它的作用是,分配一段可以存放数据的连续内存区域。 var buf = new ArrayBuffer(32); 上面代码生成了一段32字节的内存区域。 ArrayBuffer对象的byteLength属性,返回所分配的内存区域的字节长度。 var buffer = new ArrayBuffer(32); buffer.byteLength // 32 如果要分配的内存区域很大,有可能分配失败(因为没有那么多的连续空余内存),所以有必要检查是否分配成功。 if (buffer.byteLength === n) { // 成功 } else { // 失败 ArrayBuffer对象有一个slice方法,允许将内存区域的一部分,拷贝生成一个新的ArrayBuffer对象。 var buffer = new ArrayBuffer(8); var newBuffer = buffer.slice(0,3); 上面代码拷贝buffer对象的前3个字节,生成一个新的ArrayBuffer对象。slice方法其实包含两步,第一步是先分配一段新内存,第二步是将原来那个ArrayBuffer对象拷贝过去。 slice方法接受两个参数,第一个参数表示拷贝开始的字节序号,第二个参数表示拷贝截止的字节序号。如果省略第二个参数,则默认到原ArrayBuffer对象的结尾。 除了slice方法,ArrayBuffer对象不提供任何直接读写内存的方法,只允许在其上方建立视图,然后通过视图读写。 ## 视图 ### 视图的生成 ArrayBuffer作为内存区域,可以存放多种类型的数据。不同数据有不同的存储方式,这就叫做“视图”。目前,JavaScript提供以下类型的视图: * Int8Array:8位有符号整数,长度1个字节。 * Uint8Array:8位无符号整数,长度1个字节。 * Int16Array:16位有符号整数,长度2个字节。 * Uint16Array:16位无符号整数,长度2个字节。 * Int32Array:32位有符号整数,长度4个字节。 * Uint32Array:32位无符号整数,长度4个字节。 * Float32Array:32位浮点数,长度4个字节。 * Float64Array:64位浮点数,长度8个字节。 每一种视图都有一个BYTES_PER_ELEMENT常数,表示这种数据类型占据的字节数。 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 每一种视图都是一个构造函数,有多种方法可以生成: (1)在ArrayBuffer对象之上生成视图。 同一个ArrayBuffer对象之上,可以根据不同的数据类型,建立多个视图。 // 创建一个8字节的ArrayBuffer var b = new ArrayBuffer(8); // 创建一个指向b的Int32视图,开始于字节0,直到缓冲区的末尾 var v1 = new Int32Array(b); // 创建一个指向b的Uint8视图,开始于字节2,直到缓冲区的末尾 var v2 = new Uint8Array(b, 2); // 创建一个指向b的Int16视图,开始于字节2,长度为2 var v3 = new Int16Array(b, 2, 2); 上面代码在一段长度为8个字节的内存(b)之上,生成了三个视图:v1、v2和v3。视图的构造函数可以接受三个参数: * 第一个参数:视图对应的底层ArrayBuffer对象,该参数是必需的。 * 第二个参数:视图开始的字节序号,默认从0开始。 * 第三个参数:视图包含的数据个数,默认直到本段内存区域结束。 因此,v1、v2和v3是重叠:v1[0]是一个32位整数,指向字节0~字节3;v2[0]是一个8位无符号整数,指向字节2;v3[0]是一个16位整数,指向字节2~字节3。只要任何一个视图对内存有所修改,就会在另外两个视图上反应出来。 (2)直接生成。 视图还可以不通过ArrayBuffer对象,直接分配内存而生成。 var f64a = new Float64Array(8); f64a[0] = 10; f64a[1] = 20; f64a[2] = f64a[0] + f64a[1]; 上面代码生成一个8个成员的Float64Array数组(共64字节),然后依次对每个成员赋值。这时,视图构造函数的参数就是成员的个数。可以看到,视图数组的赋值操作与普通数组的操作毫无两样。 (3)将普通数组转为视图数组。 将一个数据类型符合要求的普通数组,传入构造函数,也能直接生成视图。 var typedArray = new Uint8Array( [ 1, 2, 3, 4 ] ); 上面代码将一个普通的数组,赋值给一个新生成的8位无符号整数的视图数组。 视图数组也可以转换回普通数组。 var normalArray = Array.apply( [], typedArray ); ### 视图的操作 建立了视图以后,就可以进行各种操作了。这里需要明确的是,视图其实就是普通数组,语法完全没有什么不同,只不过它直接针对内存进行操作,而且每个成员都有确定的数据类型。所以,视图就被叫做“类型化数组”。 (1)数组操作 普通数组的操作方法和属性,对类型化数组完全适用。 var buffer = new ArrayBuffer(16); var int32View = new Int32Array(buffer); for (var i=0; i 第一章 导论
  • 1.1 前言
  • 1.2 为什么学习JavaScript?
  • 1.3 JavaScript的历史
  • 第二章 基本语法
  • 2.1 语法概述
  • 2.2 数值
  • 2.3 字符串
  • 2.4 对象
  • 2.5 数组
  • 2.6 函数
  • 2.7 运算符
  • 2.8 数据类型转换
  • 2.9 错误处理机制
  • 2.10 JavaScript 编程风格
  • 第三章 标准库
  • 3.1 Object对象
  • 3.2 Array 对象
  • 3.3 包装对象和Boolean对象
  • 3.4 Number对象
  • 3.5 String对象
  • 3.6 Math对象
  • 3.7 Date对象
  • 3.8 RegExp对象
  • 3.9 JSON对象
  • 3.10 ArrayBuffer:类型化数组
  • 第四章 面向对象编程
  • 4.1 概述
  • 4.2 封装
  • 4.3 继承
  • 4.4 模块化编程
  • 第五章 DOM
  • 5.1 Node节点
  • 5.2 document节点
  • 5.3 Element对象
  • 5.4 Text节点和DocumentFragment节点
  • 5.5 Event对象
  • 5.6 CSS操作
  • 5.7 Mutation Observer
  • 第六章 浏览器对象
  • 6.1 浏览器的JavaScript引擎
  • 6.2 定时器
  • 6.3 window对象
  • 6.4 history对象
  • 6.5 Ajax
  • 6.6 同域限制和window.postMessage方法
  • 6.7 Web Storage:浏览器端数据储存机制
  • 6.8 IndexedDB:浏览器端数据库
  • 6.9 Web Notifications API
  • 6.10 Performance API
  • 6.11 移动设备API
  • 第七章 HTML网页的API
  • 7.1 HTML网页元素
  • 7.2 Canvas API
  • 7.3 SVG 图像
  • 7.4 表单
  • 7.5 文件和二进制数据的操作
  • 7.6 Web Worker
  • 7.7 SSE:服务器发送事件
  • 7.8 Page Visibility API
  • 7.9 Fullscreen API:全屏操作
  • 7.10 Web Speech
  • 7.11 requestAnimationFrame
  • 7.12 WebSocket
  • 7.13 WebRTC
  • 7.14 Web Components
  • 第八章 开发工具
  • 8.1 console对象
  • 8.2 PhantomJS
  • 8.3 Bower:客户端库管理工具
  • 8.4 Grunt:任务自动管理工具
  • 8.5 Gulp:任务自动管理工具
  • 8.6 Browserify:浏览器加载Node.js模块
  • 8.7 RequireJS和AMD规范
  • 8.8 Source Map
  • 8.9 JavaScript 程序测试
  • 第九章 JavaScript高级语法
  • 9.1 Promise对象
  • 9.2 有限状态机
  • 9.3 MVC框架与Backbone.js
  • 9.4 严格模式
  • 9.5 ECMAScript 6 介绍
  • 10.1 JavaScript API列表
  • 草稿一:函数库
  • 11.1 Underscore.js
  • 11.2 Modernizr
  • 11.3 Datejs
  • 11.4 D3.js
  • 11.5 设计模式
  • 11.6 排序算法
  • 草稿二:jQuery
  • 12.1 jQuery概述
  • 12.2 jQuery工具方法
  • 12.3 jQuery插件开发
  • 12.4 jQuery.Deferred对象
  • 12.5 如何做到 jQuery-free?
  • 草稿三:Node.js
  • 13.1 Node.js 概述
  • 13.2 CommonJS规范
  • 13.3 package.json文件
  • 13.4 npm模块管理器
  • 13.5 fs 模块
  • 13.6 Path模块
  • 13.7 process对象
  • 13.8 Buffer对象
  • 13.9 Events模块
  • 13.10 stream接口
  • 13.11 Child Process模块
  • 13.12 Http模块
  • 13.13 assert 模块
  • 13.14 Cluster模块
  • 13.15 os模块
  • 13.16 Net模块和DNS模块
  • 13.17 Express框架
  • 13.18 Koa 框架
  •