字典中,键名最理想的情况是字符串,值可以是任何类型。但是JavaScript不是强类型的语言,所有需要将key转换为字符串。
function defaultToString(item) { if (item === null) { return 'NULL'; } else if (item === undefined) { return 'UNDEFINED'; } else if (typeof item === 'string' || item instanceof String) { return `${item}`; } return item.toString(); }
Dictionary类的骨架:
class Dictionary { constructor(toStrFn = defaultToString) { // 将key转换为字符串 this.toStrFn = toStrFn; // 将[键,值]对保存为 table[key] = {key, value} this.table = {}; } }
一些常用方法:
hasKey(key)方法会被set和remove等方法调用,需要先实现
hasKey(key) { // 如果已经存在一个给定键名的键值对,返回true,否则返回false return this.table[this.toStrFn(key)] != null; }
set方法:接收key和value作为参数。可用于添加新的值,或更新已有的值
set(key, value) { // 如果key和value不为null或undefined if (key != null && value != null) { // 获取key的字符串 const tableKey = this.toStrFn(key); // 创建一个新的键值对并将其赋值给table对象上的key属性 // 此处还需要实例化ValuePair类 this.table[tableKey] = new ValuePair(key, value); return true; } return false; }
ValuePair类定义如下:
class ValuePair { constructor(key, value) { this.key = key; this.value = value; } toString() { return `$[#${this.key}: ${this.value}]` } }
为了保存信息的需要,要保存原始的key。因此,我们不是只将value保存在字典中,而是要保存两个值:原始的key和value
实现时要先搜索key,而不是value
remove(key) { if (this.hasKey(key)) { delete this.table[this.toStrFn(key)]; return true; } return false; }
方式一:(消耗比第二种方式少)
get(key) { // 检索存储在给定key属性中的对象 const valuePair = this.table[this.toStrFn(key)]; return valuePair == null ? undefined : valuePair.value; }
方式二:
会获取两次key的字符串以及访问两次table对象:第一次是在hasKey方法中,第二次是在if语句内
get(key) { if (this.hasKey(key)) { return this.table[this.toStrFn(key)]; } return undefined; }
返回字典中所有键值对:
// ES2017引入Object的values方法 keyValues() { return Object.values(this.table); }
所有浏览器都支持的方式:
keyValues() { const valuePairs = []; for (const k in this.table) { if (this.hasKey(k)) { valuePairs.push(this.table[k]); } } return valuePairs; }
返回字典中所有(原始)键名:
keys() { // 调用所创建的keyValues方法来返回一个包含valuePair实例的数组,然后迭代每个valuePair并只返回它的key。 return this.keyValues().map(valuePair => valuePair.key); }
返回字典中包含的所有值构成的数组:
values() { return this.keyValues().map(valuePair => valuePair.value); }
forEach(callbackFn) { // 获取字典中所有valuePair构成的数组 const valuePairs = this.keyValues(); for (let i = 0; i < valuePairs.length; i++) { // 执行以参数形式传入forEach方法的callbackFn函数 const result = callbackFn(valuePairs[i].key, valuePairs[i].value); // 如果回调函数返回了false,中断forEach方法的执行,打断正在迭代valuePairs的for循环 if (result === false) { break; } } }
size() { return Object.keys(this.table).length; // 或者 // return this.keyValues().length; }
isEmpty() { return this.size() === 0; }
clear() { this.table = {}; }
toString() { if (this.isEmpty()) { return ''; } const valuePairs = this.keyValues(); let objString = `${valuePairs[0].toString()}`; for (let i = 1; i < valuePairs.length; i++) { objString = `${objString}, ${valuePairs[i].toString()}`; } return objString; }
const dictionary = new Dictionary(); dictionary.set('aaa', 'aaa@email.com'); dictionary.set('bbb', 'bbb@email.com'); dictionary.set('ccc', 'ccc@email.com'); console.log(dictionary.hasKey('aaa')); console.log(dictionary.size()); console.log(dictionary.keys()); console.log(dictionary.values()); console.log(dictionary.get('bbb')); dictionary.remove('bbb'); console.log(dictionary.keys()); console.log(dictionary.values()); console.log(dictionary.keyValues()); dictionary.forEach((k, v) => { console.log('forEach:', `key: ${k}, value: ${v}`); });