diff --git a/docs/array.md b/docs/array.md index 19ab71f..1858e6b 100644 --- a/docs/array.md +++ b/docs/array.md @@ -28,7 +28,7 @@ function add(x, y) { return x + y; } -var numbers = [4, 38]; +const numbers = [4, 38]; add(...numbers) // 42 ``` @@ -38,7 +38,7 @@ add(...numbers) // 42 ```javascript function f(v, w, x, y, z) { } -var args = [0, 1]; +const args = [0, 1]; f(-1, ...args, 2, ...[3]); ``` @@ -74,7 +74,7 @@ f.apply(null, args); function f(x, y, z) { // ... } -var args = [0, 1, 2]; +let args = [0, 1, 2]; f(...args); ``` @@ -102,8 +102,8 @@ var arr2 = [3, 4, 5]; Array.prototype.push.apply(arr1, arr2); // ES6 的写法 -var arr1 = [0, 1, 2]; -var arr2 = [3, 4, 5]; +let arr1 = [0, 1, 2]; +let arr2 = [3, 4, 5]; arr1.push(...arr2); ``` @@ -185,8 +185,8 @@ const [first, ...middle, last] = [1, 2, 3, 4, 5]; JavaScript 的函数只能返回一个值,如果需要返回多个值,只能返回数组或对象。扩展运算符提供了解决这个问题的一种变通方法。 ```javascript -var dateFields = readDateFields(database); -var d = new Date(...dateFields); +let dateFields = readDateFields(database); +let d = new Date(...dateFields); ``` 上面代码从数据库取出一行数据,通过扩展运算符,直接将其传入构造函数`Date`。 @@ -236,8 +236,8 @@ str.split('').reverse().join('') 任何 Iterator 接口的对象(参阅 Iterator 一章),都可以用扩展运算符转为真正的数组。 ```javascript -var nodeList = document.querySelectorAll('div'); -var array = [...nodeList]; +let nodeList = document.querySelectorAll('div'); +let array = [...nodeList]; ``` 上面代码中,`querySelectorAll`方法返回的是一个`nodeList`对象。它不是数组,而是一个类似数组的对象。这时,扩展运算符可以将其转为真正的数组,原因就在于`NodeList`对象实现了 Iterator 。 @@ -275,7 +275,7 @@ let arr = [...map.keys()]; // [1, 2, 3] Generator 函数运行后,返回一个遍历器对象,因此也可以使用扩展运算符。 ```javascript -var go = function*(){ +const go = function*(){ yield 1; yield 2; yield 3; @@ -289,7 +289,7 @@ var go = function*(){ 如果对没有 Iterator 接口的对象,使用扩展运算符,将会报错。 ```javascript -var obj = {a: 1, b: 2}; +const obj = {a: 1, b: 2}; let arr = [...obj]; // TypeError: Cannot spread non-iterable object ``` @@ -356,7 +356,7 @@ Array.from([1, 2, 3]) ```javascript // arguments对象 function foo() { - var args = [...arguments]; + const args = [...arguments]; } // NodeList对象 @@ -517,7 +517,7 @@ Array.prototype.copyWithin(target, start = 0, end = this.length) // {0: 1, 3: 1, length: 5} // 将2号位到数组结束,复制到0号位 -var i32a = new Int32Array([1, 2, 3, 4, 5]); +let i32a = new Int32Array([1, 2, 3, 4, 5]); i32a.copyWithin(0, 2); // Int32Array [3, 4, 5, 4, 5] diff --git a/docs/arraybuffer.md b/docs/arraybuffer.md index ef5c741..9932dc2 100644 --- a/docs/arraybuffer.md +++ b/docs/arraybuffer.md @@ -49,7 +49,7 @@ Float64|8|64位浮点数|double `ArrayBuffer`也是一个构造函数,可以分配一段可以存放数据的连续内存区域。 ```javascript -var buf = new ArrayBuffer(32); +const buf = new ArrayBuffer(32); ``` 上面代码生成了一段32字节的内存区域,每个字节的值默认都是0。可以看到,`ArrayBuffer`构造函数的参数是所需要的内存大小(单位字节)。 @@ -57,8 +57,8 @@ var buf = new ArrayBuffer(32); 为了读写这段内容,需要为它指定视图。`DataView`视图的创建,需要提供`ArrayBuffer`对象实例作为参数。 ```javascript -var buf = new ArrayBuffer(32); -var dataView = new DataView(buf); +const buf = new ArrayBuffer(32); +const dataView = new DataView(buf); dataView.getUint8(0) // 0 ``` @@ -67,11 +67,11 @@ dataView.getUint8(0) // 0 另一种TypedArray视图,与`DataView`视图的一个区别是,它不是一个构造函数,而是一组构造函数,代表不同的数据格式。 ```javascript -var buffer = new ArrayBuffer(12); +const buffer = new ArrayBuffer(12); -var x1 = new Int32Array(buffer); +const x1 = new Int32Array(buffer); x1[0] = 1; -var x2 = new Uint8Array(buffer); +const x2 = new Uint8Array(buffer); x2[0] = 2; x1[0] // 2 @@ -82,7 +82,7 @@ x1[0] // 2 TypedArray视图的构造函数,除了接受`ArrayBuffer`实例作为参数,还可以接受普通数组作为参数,直接分配内存生成底层的`ArrayBuffer`实例,并同时完成对这段内存的赋值。 ```javascript -var typedArray = new Uint8Array([0,1,2]); +const typedArray = new Uint8Array([0,1,2]); typedArray.length // 3 typedArray[0] = 5; @@ -96,7 +96,7 @@ typedArray // [5, 1, 2] `ArrayBuffer`实例的`byteLength`属性,返回所分配的内存区域的字节长度。 ```javascript -var buffer = new ArrayBuffer(32); +const buffer = new ArrayBuffer(32); buffer.byteLength // 32 ``` @@ -116,8 +116,8 @@ if (buffer.byteLength === n) { `ArrayBuffer`实例有一个`slice`方法,允许将内存区域的一部分,拷贝生成一个新的`ArrayBuffer`对象。 ```javascript -var buffer = new ArrayBuffer(8); -var newBuffer = buffer.slice(0, 3); +const buffer = new ArrayBuffer(8); +const newBuffer = buffer.slice(0, 3); ``` 上面代码拷贝`buffer`对象的前3个字节(从0开始,到第3个字节前面结束),生成一个新的`ArrayBuffer`对象。`slice`方法其实包含两步,第一步是先分配一段新内存,第二步是将原来那个`ArrayBuffer`对象拷贝过去。 @@ -131,10 +131,10 @@ var newBuffer = buffer.slice(0, 3); `ArrayBuffer`有一个静态方法`isView`,返回一个布尔值,表示参数是否为`ArrayBuffer`的视图实例。这个方法大致相当于判断参数,是否为TypedArray实例或`DataView`实例。 ```javascript -var buffer = new ArrayBuffer(8); +const buffer = new ArrayBuffer(8); ArrayBuffer.isView(buffer) // false -var v = new Int32Array(buffer); +const v = new Int32Array(buffer); ArrayBuffer.isView(v) // true ``` @@ -175,16 +175,16 @@ TypedArray数组提供9种构造函数,用来生成相应类型的数组实例 ```javascript // 创建一个8字节的ArrayBuffer -var b = new ArrayBuffer(8); +const b = new ArrayBuffer(8); // 创建一个指向b的Int32视图,开始于字节0,直到缓冲区的末尾 -var v1 = new Int32Array(b); +const v1 = new Int32Array(b); // 创建一个指向b的Uint8视图,开始于字节2,直到缓冲区的末尾 -var v2 = new Uint8Array(b, 2); +const v2 = new Uint8Array(b, 2); // 创建一个指向b的Int16视图,开始于字节2,长度为2 -var v3 = new Int16Array(b, 2, 2); +const v3 = new Int16Array(b, 2, 2); ``` 上面代码在一段长度为8个字节的内存(`b`)之上,生成了三个视图:`v1`、`v2`和`v3`。 @@ -200,8 +200,8 @@ var v3 = new Int16Array(b, 2, 2); 注意,`byteOffset`必须与所要建立的数据类型一致,否则会报错。 ```javascript -var buffer = new ArrayBuffer(8); -var i16 = new Int16Array(buffer, 1); +const buffer = new ArrayBuffer(8); +const i16 = new Int16Array(buffer, 1); // Uncaught RangeError: start offset of Int16Array should be a multiple of 2 ``` @@ -214,7 +214,7 @@ var i16 = new Int16Array(buffer, 1); 视图还可以不通过`ArrayBuffer`对象,直接分配内存而生成。 ```javascript -var f64a = new Float64Array(8); +const f64a = new Float64Array(8); f64a[0] = 10; f64a[1] = 20; f64a[2] = f64a[0] + f64a[1]; @@ -227,7 +227,7 @@ f64a[2] = f64a[0] + f64a[1]; TypedArray数组的构造函数,可以接受另一个TypedArray实例作为参数。 ```javascript -var typedArray = new Int8Array(new Uint8Array(4)); +const typedArray = new Int8Array(new Uint8Array(4)); ``` 上面代码中,`Int8Array`构造函数接受一个`Uint8Array`实例作为参数。 @@ -235,8 +235,8 @@ var typedArray = new Int8Array(new Uint8Array(4)); 注意,此时生成的新数组,只是复制了参数数组的值,对应的底层内存是不一样的。新数组会开辟一段新的内存储存数据,不会在原数组的内存之上建立视图。 ```javascript -var x = new Int8Array([1, 1]); -var y = new Int8Array(x); +const x = new Int8Array([1, 1]); +const y = new Int8Array(x); x[0] // 1 y[0] // 1 @@ -249,8 +249,8 @@ y[0] // 1 如果想基于同一段内存,构造不同的视图,可以采用下面的写法。 ```javascript -var x = new Int8Array([1, 1]); -var y = new Int8Array(x.buffer); +const x = new Int8Array([1, 1]); +const y = new Int8Array(x.buffer); x[0] // 1 y[0] // 1 @@ -263,7 +263,7 @@ y[0] // 2 构造函数的参数也可以是一个普通数组,然后直接生成TypedArray实例。 ```javascript -var typedArray = new Uint8Array([1, 2, 3, 4]); +const typedArray = new Uint8Array([1, 2, 3, 4]); ``` 注意,这时TypedArray视图会重新开辟内存,不会在原数组的内存上建立视图。 @@ -273,7 +273,7 @@ var typedArray = new Uint8Array([1, 2, 3, 4]); TypedArray数组也可以转换回普通数组。 ```javascript -var normalArray = Array.prototype.slice.call(typedArray); +const normalArray = Array.prototype.slice.call(typedArray); ``` ### 数组方法 @@ -343,10 +343,10 @@ for (let byte of ui8) { 字节序指的是数值在内存中的表示方式。 ```javascript -var buffer = new ArrayBuffer(16); -var int32View = new Int32Array(buffer); +const buffer = new ArrayBuffer(16); +const int32View = new Int32Array(buffer); -for (var i = 0; i < int32View.length; i++) { +for (let i = 0; i < int32View.length; i++) { int32View[i] = i * 2; } ``` @@ -356,9 +356,9 @@ for (var i = 0; i < int32View.length; i++) { 如果在这段数据上接着建立一个16位整数的视图,则可以读出完全不一样的结果。 ```javascript -var int16View = new Int16Array(buffer); +const int16View = new Int16Array(buffer); -for (var i = 0; i < int16View.length; i++) { +for (let i = 0; i < int16View.length; i++) { console.log("Entry " + i + ": " + int16View[i]); } // Entry 0: 0 @@ -381,14 +381,14 @@ for (var i = 0; i < int16View.length; i++) { ```javascript // 假定某段buffer包含如下字节 [0x02, 0x01, 0x03, 0x07] -var buffer = new ArrayBuffer(4); -var v1 = new Uint8Array(buffer); +const buffer = new ArrayBuffer(4); +const v1 = new Uint8Array(buffer); v1[0] = 2; v1[1] = 1; v1[2] = 3; v1[3] = 7; -var uInt16View = new Uint16Array(buffer); +const uInt16View = new Uint16Array(buffer); // 计算机采用小端字节序 // 所以头两个字节等于258 @@ -453,9 +453,9 @@ function ab2str(buf) { // 字符串转为ArrayBuffer对象,参数为字符串 function str2ab(str) { - var buf = new ArrayBuffer(str.length * 2); // 每个字符占用2个字节 - var bufView = new Uint16Array(buf); - for (var i = 0, strLen = str.length; i < strLen; i++) { + const buf = new ArrayBuffer(str.length * 2); // 每个字符占用2个字节 + const bufView = new Uint16Array(buf); + for (let i = 0, strLen = str.length; i < strLen; i++) { bufView[i] = str.charCodeAt(i); } return buf; @@ -469,7 +469,7 @@ function str2ab(str) { TypedArray数组的溢出处理规则,简单来说,就是抛弃溢出的位,然后按照视图类型进行解释。 ```javascript -var uint8 = new Uint8Array(1); +const uint8 = new Uint8Array(1); uint8[0] = 256; uint8[0] // 0 @@ -499,7 +499,7 @@ uint8[0] // 255 请看下面的例子。 ```javascript -var int8 = new Int8Array(1); +const int8 = new Int8Array(1); int8[0] = 128; int8[0] // -128 @@ -513,7 +513,7 @@ int8[0] // 127 `Uint8ClampedArray`视图的溢出规则,与上面的规则不同。它规定,凡是发生正向溢出,该值一律等于当前数据类型的最大值,即255;如果发生负向溢出,该值一律等于当前数据类型的最小值,即0。 ```javascript -var uint8c = new Uint8ClampedArray(1); +const uint8c = new Uint8ClampedArray(1); uint8c[0] = 256; uint8c[0] // 255 @@ -529,8 +529,8 @@ uint8c[0] // 0 TypedArray实例的`buffer`属性,返回整段内存区域对应的`ArrayBuffer`对象。该属性为只读属性。 ```javascript -var a = new Float32Array(64); -var b = new Uint8Array(a.buffer); +const a = new Float32Array(64); +const b = new Uint8Array(a.buffer); ``` 上面代码的`a`视图对象和`b`视图对象,对应同一个`ArrayBuffer`对象,即同一段内存。 @@ -540,11 +540,11 @@ var b = new Uint8Array(a.buffer); `byteLength`属性返回TypedArray数组占据的内存长度,单位为字节。`byteOffset`属性返回TypedArray数组从底层`ArrayBuffer`对象的哪个字节开始。这两个属性都是只读属性。 ```javascript -var b = new ArrayBuffer(8); +const b = new ArrayBuffer(8); -var v1 = new Int32Array(b); -var v2 = new Uint8Array(b, 2); -var v3 = new Int16Array(b, 2, 2); +const v1 = new Int32Array(b); +const v2 = new Uint8Array(b, 2); +const v3 = new Int16Array(b, 2, 2); v1.byteLength // 8 v2.byteLength // 6 @@ -560,7 +560,7 @@ v3.byteOffset // 2 `length`属性表示TypedArray数组含有多少个成员。注意将`byteLength`属性和`length`属性区分,前者是字节长度,后者是成员长度。 ```javascript -var a = new Int16Array(8); +const a = new Int16Array(8); a.length // 8 a.byteLength // 16 @@ -571,8 +571,8 @@ a.byteLength // 16 TypedArray数组的`set`方法用于复制数组(普通数组或TypedArray数组),也就是将一段内容完全复制到另一段内存。 ```javascript -var a = new Uint8Array(8); -var b = new Uint8Array(8); +const a = new Uint8Array(8); +const b = new Uint8Array(8); b.set(a); ``` @@ -582,8 +582,8 @@ b.set(a); `set`方法还可以接受第二个参数,表示从`b`对象的哪一个成员开始复制`a`对象。 ```javascript -var a = new Uint16Array(8); -var b = new Uint16Array(10); +const a = new Uint16Array(8); +const b = new Uint16Array(10); b.set(a, 2) ``` @@ -595,8 +595,8 @@ b.set(a, 2) `subarray`方法是对于TypedArray数组的一部分,再建立一个新的视图。 ```javascript -var a = new Uint16Array(8); -var b = a.subarray(2,3); +const a = new Uint16Array(8); +const b = a.subarray(2,3); a.byteLength // 16 b.byteLength // 2 @@ -655,7 +655,7 @@ Uint16Array.from([0, 1, 2]) 这个方法还可以将一种TypedArray实例,转为另一种。 ```javascript -var ui16 = Uint16Array.from(Uint8Array.of(0, 1, 2)); +const ui16 = Uint16Array.from(Uint8Array.of(0, 1, 2)); ui16 instanceof Uint16Array // true ``` @@ -676,11 +676,11 @@ Int16Array.from(Int8Array.of(127, 126, 125), x => 2 * x) 由于视图的构造函数可以指定起始位置和长度,所以在同一段内存之中,可以依次存放不同类型的数据,这叫做“复合视图”。 ```javascript -var buffer = new ArrayBuffer(24); +const buffer = new ArrayBuffer(24); -var idView = new Uint32Array(buffer, 0, 1); -var usernameView = new Uint8Array(buffer, 4, 16); -var amountDueView = new Float32Array(buffer, 20, 1); +const idView = new Uint32Array(buffer, 0, 1); +const usernameView = new Uint8Array(buffer, 4, 16); +const amountDueView = new Float32Array(buffer, 20, 1); ``` 上面代码将一个24字节长度的`ArrayBuffer`对象,分成三个部分: @@ -714,8 +714,8 @@ DataView(ArrayBuffer buffer [, 字节起始位置 [, 长度]]); 下面是一个例子。 ```javascript -var buffer = new ArrayBuffer(24); -var dv = new DataView(buffer); +const buffer = new ArrayBuffer(24); +const dv = new DataView(buffer); ``` `DataView`实例有以下属性,含义与TypedArray实例的同名方法相同。 @@ -738,17 +738,17 @@ var dv = new DataView(buffer); 这一系列`get`方法的参数都是一个字节序号(不能是负数,否则会报错),表示从哪个字节开始读取。 ```javascript -var buffer = new ArrayBuffer(24); -var dv = new DataView(buffer); +const buffer = new ArrayBuffer(24); +const dv = new DataView(buffer); // 从第1个字节读取一个8位无符号整数 -var v1 = dv.getUint8(0); +const v1 = dv.getUint8(0); // 从第2个字节读取一个16位无符号整数 -var v2 = dv.getUint16(1); +const v2 = dv.getUint16(1); // 从第4个字节读取一个16位无符号整数 -var v3 = dv.getUint16(3); +const v3 = dv.getUint16(3); ``` 上面代码读取了`ArrayBuffer`对象的前5个字节,其中有一个8位整数和两个十六位整数。 @@ -757,13 +757,13 @@ var v3 = dv.getUint16(3); ```javascript // 小端字节序 -var v1 = dv.getUint16(1, true); +const v1 = dv.getUint16(1, true); // 大端字节序 -var v2 = dv.getUint16(3, false); +const v2 = dv.getUint16(3, false); // 大端字节序 -var v3 = dv.getUint16(3); +const v3 = dv.getUint16(3); ``` DataView视图提供8个方法写入内存。 @@ -793,8 +793,8 @@ dv.setFloat32(8, 2.5, true); 如果不确定正在使用的计算机的字节序,可以采用下面的判断方式。 ```javascript -var littleEndian = (function() { - var buffer = new ArrayBuffer(2); +const littleEndian = (function() { + const buffer = new ArrayBuffer(2); new DataView(buffer).setInt16(0, 256, true); return new Int16Array(buffer)[0] === 256; })(); @@ -811,7 +811,7 @@ var littleEndian = (function() { 传统上,服务器通过AJAX操作只能返回文本数据,即`responseType`属性默认为`text`。`XMLHttpRequest`第二版`XHR2`允许服务器返回二进制数据,这时分成两种情况。如果明确知道返回的二进制数据类型,可以把返回类型(`responseType`)设为`arraybuffer`;如果不知道,就设为`blob`。 ```javascript -var xhr = new XMLHttpRequest(); +let xhr = new XMLHttpRequest(); xhr.open('GET', someUrl); xhr.responseType = 'arraybuffer'; @@ -828,9 +828,9 @@ xhr.send(); ```javascript xhr.onreadystatechange = function () { if (req.readyState === 4 ) { - var arrayResponse = xhr.response; - var dataView = new DataView(arrayResponse); - var ints = new Uint32Array(dataView.byteLength / 4); + const arrayResponse = xhr.response; + const dataView = new DataView(arrayResponse); + const ints = new Uint32Array(dataView.byteLength / 4); xhrDiv.style.backgroundColor = "#00FF00"; xhrDiv.innerText = "Array is " + ints.length + "uints long"; @@ -843,11 +843,11 @@ xhr.onreadystatechange = function () { 网页`Canvas`元素输出的二进制像素数据,就是TypedArray数组。 ```javascript -var canvas = document.getElementById('myCanvas'); -var ctx = canvas.getContext('2d'); +const canvas = document.getElementById('myCanvas'); +const ctx = canvas.getContext('2d'); -var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); -var uint8ClampedArray = imageData.data; +const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); +const uint8ClampedArray = imageData.data; ``` 需要注意的是,上面代码的`uint8ClampedArray`虽然是一个TypedArray数组,但是它的视图类型是一种针对`Canvas`元素的专有类型`Uint8ClampedArray`。这个视图类型的特点,就是专门针对颜色,把每个字节解读为无符号的8位整数,即只能取值0~255,而且发生运算的时候自动过滤高位溢出。这为图像处理带来了巨大的方便。 @@ -871,19 +871,19 @@ pixels[i] *= gamma; `WebSocket`可以通过`ArrayBuffer`,发送或接收二进制数据。 ```javascript -var socket = new WebSocket('ws://127.0.0.1:8081'); +let socket = new WebSocket('ws://127.0.0.1:8081'); socket.binaryType = 'arraybuffer'; // Wait until socket is open socket.addEventListener('open', function (event) { // Send binary data - var typedArray = new Uint8Array(4); + const typedArray = new Uint8Array(4); socket.send(typedArray.buffer); }); // Receive binary data socket.addEventListener('message', function (event) { - var arrayBuffer = event.data; + const arrayBuffer = event.data; // ··· }); ``` @@ -907,12 +907,12 @@ fetch(url) 如果知道一个文件的二进制数据类型,也可以将这个文件读取为`ArrayBuffer`对象。 ```javascript -var fileInput = document.getElementById('fileInput'); -var file = fileInput.files[0]; -var reader = new FileReader(); +const fileInput = document.getElementById('fileInput'); +const file = fileInput.files[0]; +const reader = new FileReader(); reader.readAsArrayBuffer(file); reader.onload = function () { - var arrayBuffer = reader.result; + const arrayBuffer = reader.result; // ··· }; ``` @@ -920,7 +920,7 @@ reader.onload = function () { 下面以处理bmp文件为例。假定`file`变量是一个指向bmp文件的文件对象,首先读取文件。 ```javascript -var reader = new FileReader(); +const reader = new FileReader(); reader.addEventListener("load", processimage, false); reader.readAsArrayBuffer(file); ``` @@ -929,9 +929,9 @@ reader.readAsArrayBuffer(file); ```javascript function processimage(e) { - var buffer = e.target.result; - var datav = new DataView(buffer); - var bitmap = {}; + const buffer = e.target.result; + const datav = new DataView(buffer); + const bitmap = {}; // 具体的处理步骤 } ``` @@ -967,7 +967,7 @@ bitmap.infoheader.biClrImportant = datav.getUint32(50, true); 最后处理图像本身的像素信息。 ```javascript -var start = bitmap.fileheader.bfOffBits; +const start = bitmap.fileheader.bfOffBits; bitmap.pixels = new Uint8Array(buffer, start); ``` @@ -979,7 +979,7 @@ JavaScript 是单线程的,Web worker 引入了多线程:主线程用来与 ```javascript // 主线程 -var w = new Worker('myworker.js'); +const w = new Worker('myworker.js'); ``` 上面代码中,主线程新建了一个 Worker 线程。该线程与主线程之间会有一个通信渠道,主线程通过`w.postMessage`向 Worker 线程发消息,同时通过`message`事件监听 Worker 线程的回应。 @@ -1012,7 +1012,7 @@ ES2017 引入[`SharedArrayBuffer`](https://github.com/tc39/ecmascript_sharedmem/ // 主线程 // 新建 1KB 共享内存 -var sharedBuffer = new SharedArrayBuffer(1024); +const sharedBuffer = new SharedArrayBuffer(1024); // 主线程将共享内存的地址发送出去 w.postMessage(sharedBuffer); @@ -1027,7 +1027,6 @@ Worker 线程从事件的`data`属性上面取到数据。 ```javascript // Worker 线程 -var sharedBuffer; onmessage = function (ev) { // 主线程共享的数据,就是 1KB 的共享内存 const sharedBuffer = ev.data; @@ -1045,13 +1044,13 @@ onmessage = function (ev) { ```javascript // 分配 10 万个 32 位整数占据的内存空间 -var sab = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 100000); +const sab = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 100000); // 建立 32 位整数视图 -var ia = new Int32Array(sab); // ia.length == 100000 +const ia = new Int32Array(sab); // ia.length == 100000 // 新建一个质数生成器 -var primes = new PrimeGenerator(); +const primes = new PrimeGenerator(); // 将 10 万个质数,写入这段内存空间 for ( let i=0 ; i < ia.length ; i++ ) @@ -1065,7 +1064,7 @@ Worker 线程收到数据后的处理如下。 ```javascript // Worker 线程 -var ia; +let ia; onmessage = function (ev) { ia = ev.data; console.log(ia.length); // 100000 @@ -1098,8 +1097,8 @@ console.log(ia[42]); ```javascript // 主线程 -var sab = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 100000); -var ia = new Int32Array(sab); +const sab = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 100000); +const ia = new Int32Array(sab); for (let i = 0; i < ia.length; i++) { ia[i] = primes.next(); // 将质数放入 ia diff --git a/docs/async.md b/docs/async.md index 591b9b6..65cb443 100644 --- a/docs/async.md +++ b/docs/async.md @@ -9,9 +9,9 @@ async 函数是什么?一句话,它就是 Generator 函数的语法糖。 前文有一个 Generator 函数,依次读取两个文件。 ```javascript -var fs = require('fs'); +const fs = require('fs'); -var readFile = function (fileName) { +const readFile = function (fileName) { return new Promise(function (resolve, reject) { fs.readFile(fileName, function(error, data) { if (error) return reject(error); @@ -20,9 +20,9 @@ var readFile = function (fileName) { }); }; -var gen = function* () { - var f1 = yield readFile('/etc/fstab'); - var f2 = yield readFile('/etc/shells'); +const gen = function* () { + const f1 = yield readFile('/etc/fstab'); + const f2 = yield readFile('/etc/shells'); console.log(f1.toString()); console.log(f2.toString()); }; @@ -31,9 +31,9 @@ var gen = function* () { 写成`async`函数,就是下面这样。 ```javascript -var asyncReadFile = async function () { - var f1 = await readFile('/etc/fstab'); - var f2 = await readFile('/etc/shells'); +const asyncReadFile = async function () { + const f1 = await readFile('/etc/fstab'); + const f2 = await readFile('/etc/shells'); console.log(f1.toString()); console.log(f2.toString()); }; @@ -75,8 +75,8 @@ asyncReadFile(); ```javascript async function getStockPriceByName(name) { - var symbol = await getStockSymbol(name); - var stockPrice = await getStockPrice(symbol); + const symbol = await getStockSymbol(name); + const stockPrice = await getStockPrice(symbol); return stockPrice; } @@ -318,9 +318,9 @@ async function f() { ```javascript async function main() { try { - var val1 = await firstStep(); - var val2 = await secondStep(val1); - var val3 = await thirdStep(val1, val2); + const val1 = await firstStep(); + const val2 = await secondStep(val1); + const val3 = await thirdStep(val1, val2); console.log('Final: ', val3); } @@ -503,10 +503,11 @@ function fn(args) { ```javascript function spawn(genF) { return new Promise(function(resolve, reject) { - var gen = genF(); + const gen = genF(); function step(nextF) { + let next; try { - var next = nextF(); + next = nextF(); } catch(e) { return reject(e); } @@ -536,13 +537,13 @@ function spawn(genF) { function chainAnimationsPromise(elem, animations) { // 变量ret用来保存上一个动画的返回值 - var ret = null; + let ret = null; // 新建一个空的Promise - var p = Promise.resolve(); + let p = Promise.resolve(); // 使用then方法,添加所有动画 - for(var anim of animations) { + for(let anim of animations) { p = p.then(function(val) { ret = val; return anim(elem); @@ -567,9 +568,9 @@ function chainAnimationsPromise(elem, animations) { function chainAnimationsGenerator(elem, animations) { return spawn(function*() { - var ret = null; + let ret = null; try { - for(var anim of animations) { + for(let anim of animations) { ret = yield anim(elem); } } catch(e) { @@ -587,9 +588,9 @@ function chainAnimationsGenerator(elem, animations) { ```javascript async function chainAnimationsAsync(elem, animations) { - var ret = null; + let ret = null; try { - for(var anim of animations) { + for(let anim of animations) { ret = await anim(elem); } } catch(e) { diff --git a/docs/destructuring.md b/docs/destructuring.md index 0e314ff..888a624 100644 --- a/docs/destructuring.md +++ b/docs/destructuring.md @@ -192,7 +192,7 @@ baz // undefined 如果变量名与属性名不一致,必须写成下面这样。 ```javascript -var { foo: baz } = { foo: 'aaa', bar: 'bbb' }; +let { foo: baz } = { foo: 'aaa', bar: 'bbb' }; baz // "aaa" let obj = { first: 'hello', last: 'world' }; @@ -251,7 +251,7 @@ p // ["Hello", {y: "World"}] 下面是另一个例子。 ```javascript -var node = { +const node = { loc: { start: { line: 1, @@ -260,7 +260,7 @@ var node = { } }; -var { loc, loc: { start }, loc: { start: { line }} } = node; +let { loc, loc: { start }, loc: { start: { line }} } = node; line // 1 loc // Object {start: Object} start // Object {line: 1, column: 5} @@ -642,7 +642,7 @@ jQuery.ajax = function (url, { 任何部署了Iterator接口的对象,都可以用`for...of`循环遍历。Map结构原生支持Iterator接口,配合变量的解构赋值,获取键名和键值就非常方便。 ```javascript -var map = new Map(); +const map = new Map(); map.set('first', 'hello'); map.set('second', 'world'); diff --git a/docs/function.md b/docs/function.md index eb38bcc..7f279d3 100644 --- a/docs/function.md +++ b/docs/function.md @@ -47,7 +47,7 @@ function Point(x = 0, y = 0) { this.y = y; } -var p = new Point(); +const p = new Point(); p // { x: 0, y: 0 } ``` diff --git a/docs/intro.md b/docs/intro.md index cba96fb..37fb5e8 100644 --- a/docs/intro.md +++ b/docs/intro.md @@ -10,7 +10,7 @@ ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准, 该标准从一开始就是针对 JavaScript 语言制定的,但是之所以不叫 JavaScript,有两个原因。一是商标,Java 是 Sun 公司的商标,根据授权协议,只有 Netscape 公司可以合法地使用 JavaScript 这个名字,且 JavaScript 本身也已经被 Netscape 公司注册为商标。二是想体现这门语言的制定者是 ECMA,不是 Netscape,这样有利于保证这门语言的开放性和中立性。 -因此,ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现(另外的 ECMAScript 方言还有 Jscript 和 ActionScript)。日常场合,这两个词是可以互换的。 +因此,ECMAScript 和 JavaScript 的关系是,前者是后者的规范,后者是前者的一种实现(另外的 ECMAScript 方言还有 Jscript 和 ActionScript)。日常场合,这两个词是可以互换的。 ## ES6 与 ECMAScript 2015 的关系 diff --git a/docs/object.md b/docs/object.md index 97408d4..0eb748f 100644 --- a/docs/object.md +++ b/docs/object.md @@ -5,12 +5,12 @@ ES6 允许直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。 ```javascript -var foo = 'bar'; -var baz = {foo}; +const foo = 'bar'; +const baz = {foo}; baz // {foo: "bar"} // 等同于 -var baz = {foo: foo}; +const baz = {foo: foo}; ``` 上面代码表明,ES6 允许在对象之中,直接写变量。这时,属性名为变量名, 属性值为变量的值。下面是另一个例子。 @@ -32,7 +32,7 @@ f(1, 2) // Object {x: 1, y: 2} 除了属性简写,方法也可以简写。 ```javascript -var o = { +const o = { method() { return "Hello!"; } @@ -40,7 +40,7 @@ var o = { // 等同于 -var o = { +const o = { method: function() { return "Hello!"; } @@ -50,9 +50,9 @@ var o = { 下面是一个实际的例子。 ```javascript -var birth = '2000/01/01'; +let birth = '2000/01/01'; -var Person = { +const Person = { name: '张三', @@ -69,8 +69,8 @@ var Person = { ```javascript function getPoint() { - var x = 1; - var y = 10; + const x = 1; + const y = 10; return {x, y}; } @@ -81,7 +81,7 @@ getPoint() CommonJS 模块输出一组变量,就非常合适使用简洁写法。 ```javascript -var ms = {}; +let ms = {}; function getItem (key) { return key in ms ? ms[key] : null; @@ -107,7 +107,7 @@ module.exports = { 属性的赋值器(setter)和取值器(getter),事实上也是采用这种写法。 ```javascript -var cart = { +const cart = { _wheels: 4, get wheels () { @@ -126,7 +126,7 @@ var cart = { 注意,简洁写法的属性名总是字符串,这会导致一些看上去比较奇怪的结果。 ```javascript -var obj = { +const obj = { class () {} }; @@ -142,7 +142,7 @@ var obj = { 如果某个方法的值是一个 Generator 函数,前面需要加上星号。 ```javascript -var obj = { +const obj = { * m() { yield 'hello world'; } @@ -186,9 +186,9 @@ let obj = { 下面是另一个例子。 ```javascript -var lastWord = 'last word'; +let lastWord = 'last word'; -var a = { +const a = { 'first word': 'hello', [lastWord]: 'world' }; @@ -214,13 +214,13 @@ obj.hello() // hi ```javascript // 报错 -var foo = 'bar'; -var bar = 'abc'; -var baz = { [foo] }; +const foo = 'bar'; +const bar = 'abc'; +const baz = { [foo] }; // 正确 -var foo = 'bar'; -var baz = { [foo]: 'abc'}; +const foo = 'bar'; +const baz = { [foo]: 'abc'}; ``` 注意,属性名表达式如果是一个对象,默认情况下会自动将对象转为字符串`[object Object]`,这一点要特别小心。 @@ -346,10 +346,10 @@ Object.defineProperty(Object, 'is', { `Object.assign`方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。 ```javascript -var target = { a: 1 }; +const target = { a: 1 }; -var source1 = { b: 2 }; -var source2 = { c: 3 }; +const source1 = { b: 2 }; +const source2 = { c: 3 }; Object.assign(target, source1, source2); target // {a:1, b:2, c:3} @@ -360,10 +360,10 @@ target // {a:1, b:2, c:3} 注意,如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。 ```javascript -var target = { a: 1, b: 1 }; +const target = { a: 1, b: 1 }; -var source1 = { b: 2, c: 2 }; -var source2 = { c: 3 }; +const source1 = { b: 2, c: 2 }; +const source2 = { c: 3 }; Object.assign(target, source1, source2); target // {a:1, b:2, c:3} @@ -372,7 +372,7 @@ target // {a:1, b:2, c:3} 如果只有一个参数,`Object.assign`会直接返回该参数。 ```javascript -var obj = {a: 1}; +const obj = {a: 1}; Object.assign(obj) === obj // true ``` @@ -400,11 +400,11 @@ Object.assign(obj, null) === obj // true 其他类型的值(即数值、字符串和布尔值)不在首参数,也不会报错。但是,除了字符串会以数组形式,拷贝入目标对象,其他值都不会产生效果。 ```javascript -var v1 = 'abc'; -var v2 = true; -var v3 = 10; +const v1 = 'abc'; +const v2 = true; +const v3 = 10; -var obj = Object.assign({}, v1, v2, v3); +const obj = Object.assign({}, v1, v2, v3); console.log(obj); // { "0": "a", "1": "b", "2": "c" } ``` @@ -444,8 +444,8 @@ Object.assign({ a: 'b' }, { [Symbol('c')]: 'd' }) `Object.assign`方法实行的是浅拷贝,而不是深拷贝。也就是说,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。 ```javascript -var obj1 = {a: {b: 1}}; -var obj2 = Object.assign({}, obj1); +const obj1 = {a: {b: 1}}; +const obj2 = Object.assign({}, obj1); obj1.a.b = 2; obj2.a.b // 2 @@ -456,8 +456,8 @@ obj2.a.b // 2 对于这种嵌套的对象,一旦遇到同名属性,`Object.assign`的处理方法是替换,而不是添加。 ```javascript -var target = { a: { b: 'c', d: 'e' } } -var source = { a: { b: 'hello' } } +const target = { a: { b: 'c', d: 'e' } } +const source = { a: { b: 'hello' } } Object.assign(target, source) // { a: { b: 'hello' } } ``` @@ -838,7 +838,7 @@ d.a // "a" ```javascript // es6的写法 -var obj = { +const obj = { method: function() { ... } }; obj.__proto__ = someOtherObj; @@ -895,7 +895,7 @@ Object.getPrototypeOf({ __proto__: null }) Object.setPrototypeOf(object, prototype) // 用法 -var o = Object.setPrototypeOf({}, null); +const o = Object.setPrototypeOf({}, null); ``` 该方法等同于下面的函数。 @@ -957,7 +957,7 @@ function Rectangle() { // ... } -var rec = new Rectangle(); +const rec = new Rectangle(); Object.getPrototypeOf(rec) === Rectangle.prototype // true @@ -1033,7 +1033,7 @@ for (let [key, value] of entries(obj)) { `Object.values`方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值。 ```javascript -var obj = { foo: 'bar', baz: 42 }; +const obj = { foo: 'bar', baz: 42 }; Object.values(obj) // ["bar", 42] ``` @@ -1041,7 +1041,7 @@ Object.values(obj) 返回数组的成员顺序,与本章的《属性的遍历》部分介绍的排列规则一致。 ```javascript -var obj = { 100: 'a', 2: 'b', 7: 'c' }; +const obj = { 100: 'a', 2: 'b', 7: 'c' }; Object.values(obj) // ["b", "c", "a"] ``` @@ -1051,14 +1051,14 @@ Object.values(obj) `Object.values`只返回对象自身的可遍历属性。 ```javascript -var obj = Object.create({}, {p: {value: 42}}); +const obj = Object.create({}, {p: {value: 42}}); Object.values(obj) // [] ``` 上面代码中,`Object.create`方法的第二个参数添加的对象属性(属性`p`),如果不显式声明,默认是不可遍历的,因为`p`的属性描述对象的`enumerable`默认是`false`,`Object.values`不会返回这个属性。只要把`enumerable`改成`true`,`Object.values`就会返回属性`p`的值。 ```javascript -var obj = Object.create({}, {p: +const obj = Object.create({}, {p: { value: 42, enumerable: true @@ -1095,7 +1095,7 @@ Object.values(true) // [] `Object.entries`方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组。 ```javascript -var obj = { foo: 'bar', baz: 42 }; +const obj = { foo: 'bar', baz: 42 }; Object.entries(obj) // [ ["foo", "bar"], ["baz", 42] ] ``` @@ -1127,8 +1127,8 @@ for (let [k, v] of Object.entries(obj)) { `Object.entries`方法的另一个用处是,将对象转为真正的`Map`结构。 ```javascript -var obj = { foo: 'bar', baz: 42 }; -var map = new Map(Object.entries(obj)); +const obj = { foo: 'bar', baz: 42 }; +const map = new Map(Object.entries(obj)); map // Map { foo: "bar", baz: 42 } ``` @@ -1220,7 +1220,7 @@ o3.a // undefined 下面是另一个例子。 ```javascript -var o = Object.create({ x: 1, y: 2 }); +const o = Object.create({ x: 1, y: 2 }); o.z = 3; let { x, ...{ y, z } } = o; diff --git a/docs/string.md b/docs/string.md index e2c6581..5b9375c 100644 --- a/docs/string.md +++ b/docs/string.md @@ -70,7 +70,7 @@ s.charCodeAt(1) // 57271 ES6提供了`codePointAt`方法,能够正确处理4个字节储存的字符,返回一个字符的码点。 ```javascript -var s = '𠮷a'; +let s = '𠮷a'; s.codePointAt(0) // 134071 s.codePointAt(1) // 57271 @@ -85,7 +85,7 @@ s.codePointAt(2) // 97 `codePointAt`方法返回的是码点的十进制值,如果想要十六进制的值,可以使用`toString`方法转换一下。 ```javascript -var s = '𠮷a'; +let s = '𠮷a'; s.codePointAt(0).toString(16) // "20bb7" s.codePointAt(2).toString(16) // "61" @@ -94,7 +94,7 @@ s.codePointAt(2).toString(16) // "61" 你可能注意到了,`codePointAt`方法的参数,仍然是不正确的。比如,上面代码中,字符`a`在字符串`s`的正确位置序号应该是1,但是必须向`codePointAt`方法传入2。解决这个问题的一个办法是使用`for...of`循环,因为它会正确识别32位的UTF-16字符。 ```javascript -var s = '𠮷a'; +let s = '𠮷a'; for (let ch of s) { console.log(ch.codePointAt(0).toString(16)); } @@ -153,7 +153,7 @@ for (let codePoint of 'foo') { 除了遍历字符串,这个遍历器最大的优点是可以识别大于`0xFFFF`的码点,传统的`for`循环无法识别这样的码点。 ```javascript -var text = String.fromCodePoint(0x20BB7); +let text = String.fromCodePoint(0x20BB7); for (let i = 0; i < text.length; i++) { console.log(text[i]); @@ -236,7 +236,7 @@ ES6 提供字符串实例的`normalize()`方法,用来将字符的不同表示 - **endsWith()**:返回布尔值,表示参数字符串是否在原字符串的尾部。 ```javascript -var s = 'Hello world!'; +let s = 'Hello world!'; s.startsWith('Hello') // true s.endsWith('!') // true @@ -246,7 +246,7 @@ s.includes('o') // true 这三个方法都支持第二个参数,表示开始搜索的位置。 ```javascript -var s = 'Hello world!'; +let s = 'Hello world!'; s.startsWith('world', 6) // true s.endsWith('Hello', 5) // true @@ -386,14 +386,14 @@ console.log(`string text line 1 string text line 2`); // 字符串中嵌入变量 -var name = "Bob", time = "today"; +let name = "Bob", time = "today"; `Hello ${name}, how are you ${time}?` ``` 上面代码中的模板字符串,都是用反引号表示。如果在模板字符串中需要使用反引号,则前面要用反斜杠转义。 ```javascript -var greeting = `\`Yo\` World!`; +let greeting = `\`Yo\` World!`; ``` 如果使用模板字符串表示多行字符串,所有的空格和缩进都会被保留在输出之中。 @@ -439,8 +439,8 @@ function authorize(user, action) { 大括号内部可以放入任意的JavaScript表达式,可以进行运算,以及引用对象属性。 ```javascript -var x = 1; -var y = 2; +let x = 1; +let y = 2; `${x} + ${y} = ${x + y}` // "1 + 2 = 3" @@ -448,7 +448,7 @@ var y = 2; `${x} + ${y * 2} = ${x + y * 2}` // "1 + 4 = 5" -var obj = {x: 1, y: 2}; +let obj = {x: 1, y: 2}; `${obj.x + obj.y}` // "3" ``` @@ -470,7 +470,7 @@ function fn() { ```javascript // 变量place没有声明 -var msg = `Hello, ${place}`; +let msg = `Hello, ${place}`; // 报错 ``` @@ -533,9 +533,9 @@ func('Jack') // "Hello Jack!" 下面,我们来看一个通过模板字符串,生成正式模板的实例。 ```javascript -var template = ` +let template = `
${sender} has sent you a message.
`; function SaferHTML(templateData) { - var s = templateData[0]; - for (var i = 1; i < arguments.length; i++) { - var arg = String(arguments[i]); + let s = templateData[0]; + for (let i = 1; i < arguments.length; i++) { + let arg = String(arguments[i]); // Escape special characters in the substitution. s += arg.replace(/&/g, "&") @@ -777,8 +777,8 @@ function SaferHTML(templateData) { 上面代码中,`sender`变量往往是用户提供的,经过`SaferHTML`函数处理,里面的特殊字符都会被转义。 ```javascript -var sender = ''; // 恶意代码 -var message = SaferHTML`${sender} has sent you a message.
`; +let sender = ''; // 恶意代码 +let message = SaferHTML`${sender} has sent you a message.
`; message //<script>alert("abc")</script> has sent you a message.
@@ -797,7 +797,7 @@ i18n`Welcome to ${siteName}, you are visitor number ${visitorNumber}!` ```javascript // 下面的hashTemplate函数 // 是一个自定义的模板处理函数 -var libraryHtml = hashTemplate` +let libraryHtml = hashTemplate`