ES6小记(3)
ES6小计(3)
10. Proxy
和Reflect
10.1 Proxy
Proxy
用于修改目标对象的某些默认行为,在语言层做出改变。Proxy
可理解为对目标对象外做一层拦截。了解即可。
let target = {}
let proxy = new Proxy(target, {
get: function(target, property) {
return 35
},
set: function(target, key, value, receiver) {
return Reflect.set(target, key, value, receiver)
}
})
proxy.time // 35
proxy.name // 35
构造函数new Proxy(target, handler)
接收两个参数,target目标对象,handler配置操作对象,用于定义代理的动作。要是Proxy
有用,使用时需要针对Proxy
实例进行操作,而不是target
对象。Proxy
支持的拦截操作包含:get
、set
、has
、deleteProperty
、enumerate
、hasOwn
、ownKeys
、Object.keys()
、getOwnPropertyDescriptior
、definProperty
、preventExtensions
、getPrototypeOf
、isExtensible
、setPrototypeOf
、apply
、construct
。
10.2 Reflect
Reflect
对象有同Proxy
代理的相同的方法,Reflect
对象用于获取被代理的对象的默认行为,故一般Proxy
代理内,均会用Reflex
执行默认行为。
11. 二进制数组
二进制数组由3类对象组成:ArrayBuffer对象、TypedArray视图、DataView视图。
TypedArray视图支持9种数据类型:
|数据类型|字节长度|含义 |对应C语言类型 |
|Int8 |1 |8位带符号整数 |signed char |
|Uint8 |1 |8位无符号整数 |unsigned char |
|Uint8C |1 |8位无符号整数 |unsigned char |
|Int16 |2 |16位带符号整数 |short |
|Uint16 |2 |16位无符号整数 |unsigned char |
|Int32 |4 |32位带符号整数 |int |
|Uint32 |4 |32位无符号整数 |unsigned int |
|Float32 |4 |32位浮点数 |float |
|Float64 |8 |64位浮点数 |double |
11.1 ArrayBuffer对象
ArrayBuffer对象代表存储二进制数据的一段内存,不能直接读写,只能通过视图读写。创建ArrayBuffer对象用new ArrayBuffer(length)
构造函数创建,lengt代表分配的内存字节空间长度。
let buffer = new ArrayBuffer(12)
let x1 = new Int32Array(buffer)
x1[0] = 1
let x2 = new Uint8Array(buffer) // x1,x2均是代表同一段二进制空间,只是表示的视图不同,故内存空间变化后,两个都变。
x2[0] = 2
x1[0] // 2
node的Buffer对象其实就是Uint8Array视图对象的另一种封装。在node里,使用Buffer对象更为方便。
TypedArray视图除了接收ArrayType作为实例外,也可以直接接收普通数组作为参数,生成底层ArrayBuffer实例,完成对内存的赋值。
let typedArray = new Uint8Array([0, 1, 2])
typedArray.length // 3
typedArray[0] = 5
typedArray // [5, 1, 2]
ArrayBuffer.prototype.byteLength
,ArrayBuffer实例的byteLength
属性返回所分配内存空间的字节长度。注意若ArrayBuffer分配的内存空间很大,有可能分配失败,故可以用byteLength
检查内存分配是否如逾期,是否成功。
ArrayBuffer.prototype.slice(startIndex, endIndex)
,ArrayBuffer实例所在的内存空间的复制,返回一个新的ArrayBuffer实例,新的内存空间。
类似于String.prototype.slice()
。除slice
方法外,ArrayBuffer对象不提供任何其他直接读写内存的方法,只能通过视图对象。
ArrayBuffer.isView()
,判断传入对象是否是一个视图对象。是,返回true
;不是,返回false
。
11.2 TypedArray视图
TypedArray视图的数组成员为同一数据类型。目前TypedArray视图一共9种,每种均是一种构造函数。Int8Array
:8位有符号整数,1个字节长度;Uint8Array
:8位无符号整数,1个字节长度;Uint8ClampedArray
:8位无符号整数,1个字节长度,溢出处理不同;Int16Array
:16位有符号整数,2个字节长度;Uint8Array
:16位无符号整数,2个字节长度;Int32Array
:32位有符号整数,4个字节长度;Uint32Array
:32位无符号整数,4个字节长度;Float32Array
:32位浮点数,4个字节长度;Float32Array
:32位浮点数,4个字节长度;
用这9个构造函数生成的数组,统称为TypedArray视图。该数组成员类型唯一,连续,不会有空位,默认值为0,数组存储的是指向buffer内存的指针。
字节序:二进制数据低位在前为小端字节序,高位在前为大端字节序。这直接影响读数。TypedArray只能处理小端字节序。大端字节序需要用DataArray视图去定义处理。
11.3 DataView视图
DataView视图可以根据读取内容的方式不同而获取不同数据展示方式。
var buffer = new ArrayBuffer(24)
var dv = new DataView(buffer)
var v1 = dv.getUint16(1, true) // 从第二个字节读取一个16位无符号整数,小端字节序
var v2 = dv.getUint16(3, false) // 从第四个字节读取一个16位无符号整数,大端字节序
var v2 = dv.getUint16(3) // 从第四个字节读取一个16位无符号整数,大端字节序
dv.setInt32(0, 25, false) // 在第一个字节,以大端字节序写入值为25的32位整数
DataView实例读取内存方法:
getInt8, getUint8, getInt16, getUint16, getInt32, getUint32, getFloat32, getFloat64
DataView实例写内存的方法:
setInt8, setUint8, setInt16, setUint16, setInt32, setUint32, setFloat32, setFloat64
12. Set和Map数据结构
12.1 Set
Set是一个类似于数组的解构,其实可以理解为一个具有Iterator接口的对象。Set成员值是唯一的,没有重复。
var s = new Set()
[2, 3, 4, 5, 4, 2, 2].map(x => s.add(x))
for (i of s) { console.log(i) } // 2 3 4 5
var set = new Set([1, 2, 3, 4, 4])
[...set] // [1, 2, 3, 4]
set.size // 4
Array.from(set) // [1, 2, 3, 4]
向Set对象添加成员时,不会发生类型转换,但NaN会判断为相等。Set对象方法如下:add(value)
添加成员,返回成员总数。delete(value)
删除某个成员,返回boolean值,是否删除成功。has(value)
返回boolean,是否为Set成员。clear()
清除所有成员,无返回值。
Set对象的遍历方法:keys()
返回一个键名的遍历器。values()
返回一个键值的遍历器。entries()
返回一个键值对的遍历器,意义不大。forEach()
使用回调遍历每个成员。
因Set解构的键名和键值相同,故keys()
和values()
返回值一样。entries()
每次输出一个数组[key, value]
,key和value值一样。
注意使用数组与Set对象的相互转换,可以让Set解构使用数组的各种方法。
let set = new Set(['red', 'green', 'blue'])
for (let item of set.keys()) { console.log(item) }
for (let item of set.values()) { console.log(item) }
for (let item of set) { console.log(item) }
// 上诉3种方法结果一致
用Set解构可以很容易实现并集、交集、差集。
let a = new Set([1, 2, 3])
let b = new Set([4, 2, 3])
let union = new Set([...a, ...b]) // 并集
let intersect = new Set([...a].filter(x => b.has(x))) // 交集
let difference = new Set([...a].filter(x => !b.has(x))) // 差集,a-b
12.2 WeakSet
WeakSet解构也是不重复的值的结合,不过值只能为对象。内部对象的引用为若引用,垃圾回收机制不会计算WeakSet对成员对象的应用。不能遍历。没有size
属性。感觉意义不是很大。
12.3 Map结构
js中对象的键名只能为字符串或者Symbol
(es6新增),Map结构与普通对象类似,但是可以以对象作为键名。
var m = new Map()
var o = {p: 'hello'}
m.set(o, 'content')
m.get(o) // content
m.has(o) // true
m.delete(o) // true
m.has(o) // false
Map()
构造函数也可以接收一个数组,数组成员是键名和键值的数组。
var map = new Map([['name', '张三'], ['title', 'author']])
map.size // 2
map.has('name') // true
map.get('name') // 张三
map.has('title') // true
map.get('title') // author
重复设置键时,后面的会覆盖前面的;以对象为键时,注意对象引用为同一个时,才会认为是同一个键。+0和-0视为同一个,NaN和NaN视为同一个键。
Map实例let m = new Map()
的属性和方法:m.size
返回成员数目。m.set(key, value)
设置key对应的键值,返回整个Map实例。m.get(key)
返回key的键值,若没有此键,则返回undefined
。m.has(key)
返回boolean
,表示该键是否在Map中。m.delete(key)
删除key键,返回boolean
,表示操作成功或失败。
Map遍历同Set遍历很相似,只不过键名和键值一般不一致:keys()
返回一个键名的遍历器。values()
返回一个键值的遍历器。entries()
返回一个键值对的遍历器,意义不大。forEach()
使用回调遍历每个成员。
Map相关数据结构转换:
Map转数组:用扩展运算符
let myMap = new Map().set(true, 7).set({foo: 3}, ['abc'])
[...myMap] // [[true, 7], [{foo: 3}, ['abc']]]
数组转Map,构造函数传入数组即可。
Map转对象,遍历一遍赋值即可,同理对象转Map也是。
12.4 WeakMap
WeakMap结构与Map结构基本类似,不过它只接收对象作为键名,键名指向的对象不计入引用次数,不会对垃圾回收造成影响。
TO BE CONTINUED!