@GivenCui
2016-06-04T20:04:50.000000Z
字数 4508
阅读 1027
js高级
JS对象包括字面量对象和 new Object() 创建出来的对象
JavaScript的对象(Object),本质上是键值对的集合(Hash结构),但是只能用字符串当作键。这给它的使用带来了很大的限制。
var dog = {5 : "我是卧底,我实际是字符串"};
dog.name = "随便叫";
console.log(dog.name); // 随便叫
console.log(typeof name); // string
console.log(dog["5"]) // 我是卧底,我实际是字符串
// 侧面说明默认把5转换成了"5"
/*******Demo2 对象不能作为字面量对象的键********/
var data = {};
var element = document.getElementById("myDiv");
data[element] = metadata;
data["[Object HTMLDivElement]"] // metadata
// 上面代码原意是将一个DOM节点作为对象data的键,但是由于对象只接受字符串作为键名,所以element被自动转为字符串[Object HTMLDivElement]。
ES6提供了Map数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object结构提供了“字符串—值”的对应,Map结构提供了“值—值”的对应,是一种更完善的Hash结构实现。如果你需要“键值对”的数据结构,Map比Object更合适。
Map和其它语言的字典的概念一模一样.
Map的数据形式是一个二维数组
JS中的Map和字面量对象的用法基本一样,可以存储诸如Number, String, Object等
- map是一种红黑树的数据结构
- map中的键是唯一的
语法:
1.new Map()创建, set()动态添加
2.new Map(参数),参数为二维数组
var map = new Map([['a','刘'],['b','张']])
// 语法2二维数组作为参数的内部实现原理
var items = [
["a", "刘"],
["b", "张"]
];
var map = new Map();
items.forEach(([key, value]) => map.set(key, value));
// 接受二维数组作为参数
var map = new Map([
["staff1" , "部门名称"],
["staff2" , "部门名称"],
["staff3" , "部门名称"],
["staff4" , "部门名称"],
["staff5" , "部门名称"],
]);
/*
通过console.log(map),在控制台打印出map:
显示为:
Map { staff1: "部门名称", staff2: "部门名称", staff3: "部门名称", staff4: "部门名称", staff5: "部门名称" };
发现内部实现同字面量对象
*/
1、size 属性返回成员数
2、clear() 该方法清除所有成员,没有返回值
3、has(key)
4、get(key)
5、set(key,value) 为key设置键值,返回值实例本身,所以可以采用链式写法
// set()方法的链式写法
let map = new Map()
.set(1, 'a')
.set(2, 'b')
.set(3, 'c');
console.log(map);
6、delete(key) 删除key, 返回值为true/false
var m = new Map();
var o = {p: "Hello World"}; //一个字面量对象
m.set(o, "content") // set方法添加, o对象作为键
m.get(o) // 查询键o的值 "content"
m.has(o) // true has方法判断键是否存在,返回值为true/false
m.delete(o) // true 删除"键", 返回值是true/false
m.has(o) // false 证明元素不存在
// 可以添加键值对儿
// 值可以是数组、字符串、对象等
map.set("c", "王");
// 通过某个键获得某个值
map.get("c");
// 如果添加的键已经存在, 那么会把该键的值覆盖掉. 不会有重复的键出现.
// 一句话就是, 键不可重复添加
用到forEach()
对象.forEach(function (元素, key或index , 调用的对象本身) {
// 每个元素都执行的代码
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title> 字典Map </title>
</head>
<body>
<script type="text/javascript">
// 字典Map
// 创建一个map对象
var map = new Map();
// 给map添加键值对
map.set("a", "阿拉斯加");
map.set("b", "编写");
map.set("c", {name : "张xx",age : 18});
// 添加个重复的键
map.set("a","重复就覆盖");
console.log(map);
// 通过键获得值
console.log(map.get("a"));
// forEach 遍历Map
map.forEach(function (value, key ,map123) {
// 三个参数
// value: map当前键对应的值
// key: map当前的键
// 对象本身,叫什么都行
console.log("键: " + key);
console.log("值: " + value);
});
// 数组调用forEach
var arr = [1,"你好",false];
arr.forEach(function (element, idx ,arr123) {
console.log(element);
})
</script>
</body>
</html>
如果对同一个键多次赋值,后面的值将覆盖前面的值。
let map = new Map();
map
.set(1, 'aaa')
.set(1, 'bbb');
map.get(1) // "bbb"
上面代码对键1连续赋值两次,后一次的值覆盖前一次的值。
只有对同一个对象的引用,Map结构才将其视为同一个键。这一点要非常小心。
var map = new Map();
map.set(['a'], 555);
map.get(['a']) // undefined
上面代码的set和get方法,表面是针对同一个键,但实际上这是两个值,内存地址是不一样的,因此get方法无法读取该键,返回undefined。
同理,同样的值的两个实例,在Map结构中被视为两个键。
var map = new Map();
var k1 = ['a'];
var k2 = ['a'];
map
.set(k1, 111)
.set(k2, 222);
map.get(k1) // 111
map.get(k2) // 222
上面代码中,变量k1和k2的值是一样的,但是它们在Map结构中被视为两个键。
由上可知,Map的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键。这就解决了同名属性碰撞(clash)的问题,我们扩展别人的库的时候,如果使用对象作为键名,就不用担心自己的属性与原作者的属性同名。
前面已经提过,Map转为数组最方便的方法,就是使用扩展运算符(...)。
let myMap = new Map().set(true, 7).set({foo: 3}, ['abc']);
[...myMap]
// [ [ true, 7 ], [ { foo: 3 }, [ 'abc' ] ] ]
将数组转入Map构造函数,就可以转为Map。
new Map([[true, 7], [{foo: 3}, ['abc']]])
// Map {true => 7, Object {foo: 3} => ['abc']}
如果所有Map的键都是字符串,它可以转为对象。
function strMapToObj(strMap) {
let obj = Object.create(null);
for (let [k,v] of strMap) {
obj[k] = v;
}
return obj;
}
let myMap = new Map().set('yes', true).set('no', false);
strMapToObj(myMap)
// { yes: true, no: false }
function objToStrMap(obj) {
let strMap = new Map();
for (let k of Object.keys(obj)) {
strMap.set(k, obj[k]);
}
return strMap;
}
objToStrMap({yes: true, no: false})
// [ [ 'yes', true ], [ 'no', false ] ]
Map转为JSON要区分两种情况。一种情况是,Map的键名都是字符串,这时可以选择转为对象JSON。
function strMapToJson(strMap) {
return JSON.stringify(strMapToObj(strMap));
}
let myMap = new Map().set('yes', true).set('no', false);
strMapToJson(myMap)
// '{"yes":true,"no":false}'
JSON转为Map,正常情况下,所有键名都是字符串。
function jsonToStrMap(jsonStr) {
return objToStrMap(JSON.parse(jsonStr));
}
jsonToStrMap('{"yes":true,"no":false}')
// Map {'yes' => true, 'no' => false}
但是,有一种特殊情况,整个JSON就是一个数组,且每个数组成员本身,又是一个有两个成员的数组。这时,它可以一一对应地转为Map。这往往是数组转为JSON的逆操作。
function jsonToMap(jsonStr) {
return new Map(JSON.parse(jsonStr));
}
jsonToMap('[[true,7],[{"foo":3},["abc"]]]')
// Map {true => 7, Object {foo: 3} => ['abc']}