Object
- 表达式上下文指的是期待返回值的上下文
// 对象字面量表示法
let person = {// 这个左大括号表示对象字面量开始 因为他出现在表达式上下文中
name:"cara",
age:25,
5:true// 在对象字面量表示法中 属性名可以是字符串或数值 数值属性会自动转换为字符串
// 使用对象字面量表示法定义对象时 并不会实际调用Object构造函数
}
同样是左大括号 如果出现在语句上下文中 比如if语句的条件后面 则表示一个语句块的开始
- 虽然属性一般通过点语法来存取 这也是面向对象语言的惯例 但也可以使用中括号来存取属性 在使用中括号时 要在括号内使用属性名的字符串形式
Array
- 数组中每个槽位可以存储任意类型的数据 这意味着可以创建一个数组 他的第一个元素是字符串 第二个元素数值 第三个时对象 ECMAScript数组也是动态大小的 会随着数据添加而自动增长
- 创建数组的方式:
let colors = new Array();// 创建一个数组
// 创建数组时可以给构造函数传一个值 这个值如果是数值 则会创建一个长度为指定数值的数组
let colors = new Array(20);// 创建一个初始长度为20的数组
// 这个值如果是其他类型 则会创建一个只包含该特定值的数组
let colors = new Array("red","blue","green");// ["red","blue","green"]
// 上面的几种方法也可以省略new
// 下面使用数组字面量表示法创建数组 此时不会调用Array构造函数
let colors = ["red","blue","green"];
let colors = [];
// 使用数组字面量创建数组时 可以使用遗传逗号来创建空位
let colors = [,,,];// 创建了一个包含4个元素的数组
// ES6新增方法普遍将这些空位当成存在元素 只不过值为undefined
// ES6之前的方法是否忽略这些空位因方法而异
// 由于行为不一致和存在性能隐患 因此实践中要避免使用数组空位 如果确实需要空位 则可以显式的用undefined值代替
- 用于创建数组的方法:
Array.from()
、Array.of()
- 如果把一个值设置给超过数组最大索引的索引 则数组长度会自动扩展到该索引值+1
- 通过修改length属性 可以从数组末尾删除或添加元素 如果将length设置为大于数组元素数的值 则新添加的元素都将以undefined填充
- 数组最多可以包含4294967295个元素
- 在只有一个网页(因而只有一个全局作用域)时 可以使用
instanceof
操作符检测一个对象是不是数组 如果网页里有多个框架 则可能涉及两个不同的全局执行上下文 因此就会有两个不同版本的Array构造函数 如果要把数组从一个框架传给另一个框架 则这个数组的构造函数将有别于在第二个框架内本地创建的数组 为了解决这个问题 可以使用Array.isArray()
来确定一个值是否是数组 而不用管他是在那个全局执行上下文中创建的 - 检索数组内容的方法:
(1)keys()
:返回数组索引
(2)values()
:返回数组元素
(3)entries()
:返回索引/值对 valueOf()
返回数组本身toString()
返回由数组中每个值的等效字符串拼接而成的一个由逗号分隔的字符串 也就是说 对数组的每个值都会调用其toString()
方法 以得到最终的字符串
let colors = ['red','blue','green']
console.log(colors.toString())// red,blue,green
console.log(colors.valueOf())// [ 'red', 'blue', 'green' ]
alert(colors.valueOf())// red,blue,green
// 上一行代码等同于alert(colors.valueOf().toString())
// alert()期待字符串 所以会在后台调用数组的toString()方法
toLocaleString()
方法会得到一个逗号分隔的数组值的字符串 他与前两个方法的区别是 为了得到最终的字符串 会调用数组每个值的toLocaleString()方法- 如果数组中某一项是null或undefined 则在
join()
、toLocaleString()
、valueOf()
、toString()
返回的结果中会以空字符串表示
定型数组TypedArray
- 定型数组TypedArray:特殊的包含数值类型的数组
Map
- 如果想在创建的同时初始化实例 可以给Map构造函数传入一个可迭代对象 需要包含键值对数组 键值对会按照迭代顺序插入到新映射实例中
const m = new Map();// 创建实例
// 创建实例并初始化
const m1 = new Map([
["key1", "val1"],
["key2", "val2"],
["key3", "val3"],
])
const m2 = new Map([[]])// 无论是否提供映射期待的键值对
- API:
(1)clear
:从映射中移除所有元素。
(2)delete
:从映射中移除指定的元素。
(3)forEach
:对映射中的每个元素执行指定操作。
(4)get
:返回映射中的指定元素。
(5)has
:如果映射包含指定元素,则返回 true。
(6)set
:添加一个新建元素到映射。
(7)toString
:返回映射的字符串表示形式。
(8)valueOf
:返回指定对象的原始值。
(9)Object.getOwnPropertyNames(map).length
:获取map的长度
(10)遍历Map:
let a = new Map([
['name','leo'],
['age',18]
]
for (let i of a.keys()){...};// keys():返回键名的遍历器。
for (let i of a.values()){...};// values():返回键值的遍历器。
for (let i of a.entries()){...};// entries():返回所有成员的遍历器。
a.forEach((v,k,m)=>{// forEach():遍历Map的所有成员。
console.log(`key:${k},value:${v},map:${m}`)
})
set()
方法返回Map实例 因此可以把多个操作连缀起来 包括初始化声明
const m = new Map().set("key1", "val1");
m.set("key2", "val2").set("key3", "val3")
- 与Object只能使用数值、字符串或符号作为键不同 Map可以使用任何JS数据类型作为键
- Map内部使用
SameValueZero
比较操作 基本上相当于使用严格对象相等的标准来检查键的匹配性 - 与严格相等一样 在Map实例中用作键和值的对象及其他“集合”类型 在自己的内容或属性被修改时仍然保持不变
const m = new Map();
const objKey = {}, objVal = {}, arrKey = [], arrVal = [];
m.set(objKey,objVal);
m.set(arrKey,arrVal);
objKey.foo = "foo";
objVal.bar = "bar";
arrKey.push("foo");
arrVal.push("bar");
console.log(m.get(objKey));// { bar: 'bar' }
console.log(m.get(arrKey));// [ 'bar' ]
SameValueZero
比较也可能导致意想不到的冲突
const m = new Map();
const a = 0 / "", b = 0 / "",// NaN
pz = +0,
nz = -0;
console.log(a === b);// false
console.log(pz === nz);// true
m.set(a, "foo");
m.set(pz, "bar");
console.log(m.get(b));// foo
console.log(m.get(nz));// bar
- 与Object类型的一个主要差异是 Map实例会维护键值对的插入顺序 因此可以根据插入顺序执行迭代操作
- Map实例提供一个迭代器 能以插入顺序生成[key,value]形式的数组 可以通过
entries()
方法或者Symbol.iterator
属性(他引用entries()
方法)取得Map实例的键值对
const m = new Map([
["key1", "val1"],
["key2", "val2"],
["key3", "val3"],
]);
console.log(m.entries === m[Symbol.iterator]);// true
for (const pair of m.entries()) {
console.log(pair);// [ 'key1', 'val1' ] [ 'key2', 'val2' ] [ 'key3', 'val3' ]
}
for (const pair of m[Symbol.iterator]()) {
console.log(pair)// [ 'key1', 'val1' ] [ 'key2', 'val2' ] [ 'key3', 'val3' ]
}
- 把Map实例转换为数组:
const m = new Map([
["key1", "val1"],
["key2", "val2"],
["key3", "val3"],
]);
console.log([...m]);
- 键和值在迭代器遍历时是可以修改的 但映射Map实例内部的引用则无法修改 这并不妨碍修改作为键或值的对象内部的属性 因为这样并不影响他们在实例中的身份
const m1 = new Map([["key1", "val1"]]);
for (let key of m1.keys()) {
key = "newKey";
console.log(key);//newKey
// 作为键的字符串原始值是不能修改的
console.log(m1.get("key1"));// val1
}
const keyObj = {id: 1};
const m = new Map([[keyObj, "val1"]]);
// 修改了作为键的对象的属性 但对象在映射内部仍然引用相同的值
for (let key of m.keys()) {
key.id = "newKey";
console.log(key);// { id: 'newKey' }
console.log(m.get(keyObj))// val1
}
console.log(keyObj)// { id: 'newKey' }
- Object与Map的区别:
(1)Map大约可以比Object多存储50%的键值对
(2)插入Map稍微会快点儿
(3)Object的查找速度稍微快点儿
(4)Map的delete()操作比插入查找更快 如果代码涉及大量删除操作 选Map
WeakMap
Set
- 如果想在创建的同时初始化实例 可以给Set构造函数传入一个可迭代对象 需要包含插入到新集合实例中的元素
let s = new Set();// 创建实例
// 创建实例并初始化
const s1 = new Set(["val1", "val2", "val3"])
- API:
(1)add
:添加元素
(2)delete
:删除元素 返回布尔值 表示集合中是否存在要删除的值
(3)size
:获取set中元素个数
(4)has
: 判断 Set 中是否包含某个元素
(5)遍历 Set:forEach和for of
let v = new Set()
v.add(1)
v.add(5)
v.forEach(t=>{
console.log(t)
})
let v = new Set([1,2,3,3,5])
for(let t of v) {
console.log(t)
}
- Set可以使用任何JS数据类型作为值
- Set内部使用
SameValueZero
比较操作 基本上相当于使用严格对象相等的标准来检查键的匹配性 - 与严格相等一样 用作值的对象及其他“集合”类型在自己的内容或属性被修改时仍然保持不变
const s = new Set();
const objVal = {}, arrVal = [];
s.add(objVal);
s.add(arrVal);
objVal.bar = "bar";
arrVal.push("bar");
console.log(s.has(objVal));// true
console.log(s.has(arrVal));// true
- add()和delete()操作时幂等的
- Set实例提供一个迭代器 能以插入顺序生成集合内容 可以通过values()方法及其别名方法keys()或者
Symbol.iterator
属性(他调用values()方法)取得集合内容 - 集合转数组:Array.from和解构
let v = new Set([1,2,3,3,5])
let a = Array.from(v)// a是数组
console.log([...s])// 解构
- 修改集合中值的属性不会影响其作为集合值的身份
const s1 = new Set(["val1"]);
for (let value of s1.values()) {
value = "newKey";
console.log(value);//newKey
// 字符串原始值作为值不会被修改
console.log(s1.has("val1"));// true
}
const valObj = {id: 1};
const s2 = new Set([valObj]);
// 修改值对象的属性 但对象仍然存在于集合中
for (let value of s2.values()) {
value.id = "newVal";
console.log(value);// { id: 'newVal' }
console.log(s2.has(valObj))// true
}
console.log(valObj)// { id: 'newVal' }
- 返回集合的交集 并集 差集