第四节:ES6用法之Map、RegExp、Number、Proxy
一. Map
1. 说明
ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。
2. 添加数据
let map = new Map() // 1. 添加数据 let keyObj = {} let keyFunc = function () { } let keyString = 'a string' map.set(keyString, "和键'a string'关联的值") map.set(keyObj, '和键keyObj关联的值') map.set(keyFunc, '和键keyFunc关联的值')
3. 删除数据
// 删除指定的数据 map.delete(keyObj) // 删除所有数据 map.clear()
4. 统计数据
// 统计所有 key-value 的总数 console.log(map.size) //2 // 判断是否有 key-value console.log(map.has(keyObj)) // true
5. 查询+遍历数据
//查询 console.log(map.get(keyObj)) // 和键keyObj关联的值 //4. 遍历 map.forEach((value, key) => console.log(value, key)) for (let [key, value] of map) { console.log(key, value) } for (let key of map.keys()) { console.log(key) } for (let value of map.values()) { console.log(value) } for (let [key, value] of map.entries()) { console.log(key, value) }
6. WeakMap
WeakMap结构与Map结构类似,也是用于生成键值对的集合。
// WeakMap 可以使用 set 方法添加成员 const wm1 = new WeakMap() const key = { foo: 1 } wm1.set(key, 2) wm1.get(key) // 2 // WeakMap 也可以接受一个数组, // 作为构造函数的参数 const k1 = [1, 2, 3] const k2 = [4, 5, 6] const wm2 = new WeakMap([ [k1, 'foo'], [k2, 'bar'] ]) wm2.get(k2) // "bar"
PS: WeakMap只接受对象作为键名(null除外),不接受其他类型的值作为键名。
const map = new WeakMap() map.set(1, 2) // TypeError: 1 is not an object! map.set(Symbol(), 2) // TypeError: Invalid value used as weak map key map.set(null, 2) // TypeError: Invalid value used as weak map key
二. RegExp
主要新增了y运算符和u运算符。
三. Number
1. 进制转换
{ // 1. 进制转换 // 十进制转二进制 const a = 5 console.log(a.toString(2)) // 101 // 八进制转二进制 const b = 101 console.log(parseInt(b, 2)) //2 // ES6中新的进制表示方式 { const a = 0B0101 console.log(a) //5 const b = 0O777 console.log(b) //511 } }
2. Number扩展与统一
(1). Number.isFinite()
用来检查一个数值是否为有限的(finite),即不是Infinity。
Number.isFinite(15) // true Number.isFinite(0.8) // true Number.isFinite(NaN) // false Number.isFinite(Infinity) // false Number.isFinite(-Infinity) // false Number.isFinite('foo') // false Number.isFinite('15') // false Number.isFinite(true) // false
(2). Number.isNaN()
用来检查一个值是否为NaN。
Number.isNaN(NaN) // true Number.isNaN(15) // false Number.isNaN('15') // false Number.isNaN(true) // false Number.isNaN(9 / NaN) // true Number.isNaN('true' / 0) // true Number.isNaN('true' / 'true') // true
(3). Number.parseInt()
ES6 将全局方法parseInt()移植到Number对象上面,行为完全保持不变。 这样做的目的,是逐步减少全局性方法,使得语言逐步模块化。
// ES5的写法 parseInt('12.34') // 12 // ES6的写法 Number.parseInt('12.34') // 12
(4). Number.parseFloat()
ES6 将全局方法parseFloat()移植到Number对象上面,行为完全保持不变。这样做的目的,是逐步减少全局性方法,使得语言逐步模块化。
// ES5的写法 parseFloat('123.45#') // 123.45 // ES6的写法 Number.parseFloat('123.45#') // 123.45
(5). Number.isInteger()
用来判断一个数值是否为整数。
Number.isInteger(25) // true Number.isInteger(25.1) // false Number.isInteger() // false Number.isInteger(null) // false Number.isInteger('15') // false Number.isInteger(true) // false
(6). 最大最小安全整数
//最大和最小安全整数 console.log(Number.MAX_SAFE_INTEGER); //9007199254740991 console.log(Number.MIN_SAFE_INTEGER); //-9007199254740991
(7). Number.isSafeInteger()
能够准确表示的整数范围在-2^53到2^53之间(不含两个端点),超过这个范围,无法精确表示这个值。
3. Math新增方法
(1). Math.trunc()
用于去除一个数的小数部分,返回整数部分。
console.log(Math.trunc(5.5)) //5 console.log(Math.trunc(-5.5)) //-5 console.log(Math.trunc(true)) // 1 console.log(Math.trunc(false)) // 0 console.log(Math.trunc(NaN)) // NaN console.log(Math.trunc(undefined)) // NaN console.log(Math.trunc()) // NaN
(2). Math.sign()
方法用来判断一个数到底是正数、负数、还是零。对于非数值,会先将其转换为数值。
它会返回五种值。
- 参数为正数,返回+1
- 参数为负数,返回-1
- 参数为 0,返回0
- 参数为-0,返回-0
- 其他值,返回NaN
console.log(Math.sign(5)) // 1 console.log(Math.sign(-5)) // -1 console.log(Math.sign(0)) // 0 console.log(Math.sign(NaN)) // NaN console.log(Math.sign(true)) // 1 console.log(Math.sign(false)) // 0
(3). Math.cbrt()
方法用于计算一个数的立方根。
console.log(Math.cbrt(8)) // 2 console.log(Math.cbrt('imooc')) // NaN
四. Proxy
1. 基本语法
let p = new Proxy(target, handler)
解释:
2. 场景1-读操作拦截
(1). 旧模式
//读操作拦截 let o = { name: 'xiaoming', age: 20 } console.log(o.name) // xiaoming console.log(o.age) // 20 console.log(o.from) // undefined console.log(o.from||'') // undefined的时候输出空字符串
剖析:
使用 console.log(o.from || '')的方式解决undefined的问题,代码繁琐,且观赏性不友好。
(2). Proxy模式
let o = { name: 'xiaoming', age: 20 } let handler = { get(obj, key) { return Reflect.has(obj, key) ? obj[key] : '' } } let p = new Proxy(o, handler) console.log(o.name) // xiaoming console.log(o.age) // 20 console.log(p.from) // 输出空字符串
剖析:
全局操作,代码简洁友好。
3. 场景2-只读设置
从服务端获取的数据希望是只读,不允许在任何一个环节被修改。
旧模式
// response.data 是 JSON 格式的数据,来自服务端的响应 // 在 ES5 中只能通过遍历把所有的属性设置为只读 for (let [key] of Object.entries(response.data)) { Object.defineProperty(response.data, key, { writable: false }) }
Proxy模式
let data = new Proxy(response.data, { set(obj, key, value) { return false } })
4. 场景3-格式校验
对于数据交互而言,校验是不可或缺的一个环境,传统的做法是将校验写在了业务逻辑里,导致代码耦合度较高。如果大家使用 Proxy 就可以将代码设计的非常灵活。
// Validator.js export default (obj, key, value) => { if (Reflect.has(key) && value > 20) { obj[key] = value } } import Validator from './Validator' let data = new Proxy(response.data, { set: Validator })
5. get-拦截对象属性的读取
拦截对象属性的读取,比如proxy.foo和proxy['foo']。
let arr = [7, 8, 9] arr = new Proxy(arr, { get(target, prop) { return prop in target ? target[prop] : 'error' } }) console.log(arr[1]) //8 console.log(arr[10]) //error let dict = { 'hello': '你好', 'world': '世界' } dict = new Proxy(dict, { get(target, prop) { return prop in target ? target[prop] : prop } }) console.log(dict['world']) //你好 console.log(dict['imooc']) //immooc
6. set-拦截对象属性的设置
拦截对象属性的设置,比如proxy.foo = v或proxy['foo'] = v,返回一个布尔值
let arr = [] arr = new Proxy(arr, { set(target, prop, val) { if (typeof val === 'number') { target[prop] = val return true } else { return false } } }) arr.push(5) arr.push(6) console.log(arr[0], arr[1], arr.length) //5 6 2
7. has、ownKeys、deleteProperty、apply、construct
不一一探讨了。
!
- 作 者 : Yaopengfei(姚鹏飞)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 声 明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
- 声 明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。