不重复,不相等。
Symbol函数前不能使用new命令, Symbol 值不是对象,所以不能添加属性。
Symbol 值可以作为标识符,用于对象的属性名,就能保证不会出现同名的属性。这对于一个对象由多个模块构成的情况非常有用,能防止某一个键被不小心改写或覆盖。
// 没有参数的情况
let s1 = Symbol();
let s2 = Symbol();
s1 === s2 // false
// 有参数的情况
let s1 = Symbol('foo');
let s2 = Symbol('foo');
s1 === s2 // false
提取属性值:Object.getOwnPropertySymbols()拿到symbol属性
Reflect.ownKeys().forEach()
1.属性的简洁表示法
ES6 允许直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。上面代码表明,ES6 允许在对象之中,直接写变量。这时,属性名为变量名, 属性值为变量的值。下面是另一个例子。
const foo = 'bar';
const baz = {foo};
const o = {
method() {
return "Hello!";
}
};
// 方法一
obj.foo = true;
// 方法二
obj['a' + 'bc'] = 123;
ES6 允许(表达式)作为对象的属性名,即把表达式放在方括号内。表达式还可以用于定义方法名。属性名表达式与简洁表示法,不能同时使用,会报错。
let obj = {
['h' + 'ello']() {
return 'hi'; }};
obj.hello() // hi
注意,属性名表达式与简洁表示法,不能同时使用,会报错。
函数的name属性,返回函数名。对象方法也是函数,因此也有name属性。
如果对象的方法使用了取值函数(getter)和存值函数(setter),则name属性不是在该方法上面,而是该方法的属性的描述对象的get和set属性上面,返回值是方法名前加上get和set。
const obj = {
get foo() {},
set foo(x) {}
};
obj.foo.name// TypeError: Cannot read property 'name' of undefined
const descriptor = Object.getOwnPropertyDescriptor(obj, 'foo');
descriptor.get.name // "get foo"
descriptor.set.name // "set foo"
有两种特殊情况:bind方法创造的函数,name属性返回bound加上原函数的名字;Function构造函数创造的函数,name属性返回anonymous。
(new Function()).name // "anonymous"
var doSomething = function() {
// ...
};
doSomething.bind().name // "bound doSomething"如果对象的方法是一个 Symbol 值,那么name属性返回的是这个 Symbol 值的描述。
ES6 一共有 5 种方法可以遍历对象的属性。
(1)for…in for…in循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)
(2)Object.keys(obj) 返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名。
(3)Object.getOwnPropertyNames(obj)返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名。
(4)Object.getOwnPropertySymbols(obj)返回一个数组,包含对象自身的所有 Symbol 属性的键名。
(5)Reflect.ownKeys(obj)返回一个数组,包含对象自身的所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举。
以上的 5 种方法遍历对象的键名,都遵守同样的属性遍历的次序规则。
首先遍历所有数值键,按照数值升序排列。
其次遍历所有字符串键,按照加入时间升序排列。
最后遍历所有 Symbol 键,按照加入时间升序排列。
对象的解构赋值的拷贝是浅拷贝,即如果一个键的值是复合类型的值(数组、对象、函数)、那么解构赋值拷贝的是这个值的引用,而不是这个值的副本。
Object.is就是部署这个算法的新方法。它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致。
Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。Object.assign方法实行的是浅拷贝,而不是深拷贝。也就是说,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。对于这种嵌套的对象,一旦遇到同名属性,Object.assign的处理方法是替换,而不是添加。
引入了Object.getOwnPropertyDescriptors()方法,返回指定对象所有自身属性(非继承属性)的描述对象。
Object.setPrototypeOf方法的作用与__proto__相同,用来设置一个对象的prototype对象,返回参数对象本身。它是 ES6 正式推荐的设置原型对象的方法。
Object.setPrototypeOf(object, prototype)
const o = Object.setPrototypeOf({}, null);
该方法等同于下面的函数。
function setPrototypeOf(obj, proto) {
obj.__proto__ = proto;
return obj;
}
下面是一个例子。
let proto = {};
let obj = { x: 10 };
Object.setPrototypeOf(obj, proto);
proto.y = 20;
proto.z = 40;
obj.x // 10
obj.y // 20
obj.z // 40
Object.getPrototypeOf()该方法与Object.setPrototypeOf方法配套,用于读取一个对象的原型对象。
function Rectangle() {
// ...
}
const rec = new Rectangle();
Object.getPrototypeOf(rec) === Rectangle.prototype// true
Object.setPrototypeOf(rec, Object.prototype);
Object.getPrototypeOf(rec) === Rectangle.prototype// false
Set 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。成员的值都是唯一的,没有重复的值。
Set本身是一个构造函数,用来生成 Set 数据结构。
+0 与 -0 在存储判断唯一性的时候是恒等的,所以不重复;
undefined 与 undefined 是恒等的,所以不重复;
NaN 与 NaN 是不恒等的,但是在 Set 中只能存一个,不重复。
const s = new Set();
[2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));
for (let i of s) {
console.log(i);
}
// 2 3 5 4
let mySet = new Set();
mySet.add(1); // Set(1) {1}
mySet.add(5); // Set(2) {1, 5}
mySet.add(5); // Set(2) {1, 5} 这里体现了值的唯一性
mySet.add("some text");
// Set(3) {1, 5, "some text"} 这里体现了类型的多样性
var o = {a: 1, b: 2};
mySet.add(o);
mySet.add({a: 1, b: 2});
// Set(5) {1, 5, "some text", {…}, {…}}
// 这里体现了对象之间引用不同不恒等,即使值相同,Set 也能存储
[...new Set(array)]
上面的方法也可以用于,去除字符串里面的重复字符。
[...new Set('ababbc')].join('')
Set.prototype.constructor:构造函数,默认就是Set函数。
Set.prototype.size:返回Set实例的成员总数。
Set 实例的方法分为两大类:操作方法(用于操作数据)和遍历方法(用于遍历成员)。下面先介绍四个操作方法。
add(value):添加某个值,返回 Set 结构本身。
delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
has(value):返回一个布尔值,表示该值是否为Set的成员。
clear():清除所有成员,没有返回值。
Set 结构的实例有四个遍历方法,可以用于遍历成员。
keys():返回键名的遍历器
values():返回键值的遍历器
entries():返回键值对的遍历器
forEach():使用回调函数遍历每个成员,参数为函数
需要特别指出的是,Set的遍历顺序就是插入顺序。这个特性有时非常有用,比如使用 Set 保存一个回调函数列表,调用时就能保证按照添加顺序调用。
(1)keys方法、values方法、entries方法返回的都是遍历器对象(详见《Iterator 对象》一章)。由于 Set 结构没有键名,只有键值(或者说键名和键值是同一个值),所以keys方法和values方法的行为完全一致。
1.set.add({t:1}) array.push({t:1})
2.set.has(a(被保存过的对象)) array.find(item=>item.t)
3.set.forEach(item=>item.t?item.t=3:’’) array.forEach(item=>item.t?item.t=3:’’)
4.set.forEach(item=>item.t?set.delete(item):’’)
let index=array.findIndex(item=>item.t)
array.splice(index,1)
(增删改查)
1.map.set(‘t’,1) array.push({t:1})
2.map.has(‘t’) array.find(item=>item.t)
3.map.set(‘t’,2) array.forEach(item=>item.t?item.t=3:’’)
4.map.delete(‘t’)
let index=array.findIndex(item=>item.t)
array.splice(index,1)
1.类型不同,weakSet只能存放对象
2.WeakSet 没有size属性,没有办法遍历它的成员。WeakSet 不能遍历,是因为成员都是弱引用,随时可能消失,遍历机制无法保证成员的存在。
3.foos对实例的引用,不会被计入内存回收机制,所以删除实例的时候,不用考虑foos,也不会出现内存泄漏。
对象保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
const m = new Map();
const o = {p: 'Hello World'};
m.set(o, 'content')
m.get(o) // "content"
m.has(o) // true
m.delete(o) // true
keys():返回键名的遍历器
values():返回键值的遍历器
entries():返回键值对的遍历器
forEach():使用回调函数遍历每个成员,参数为函数
set Maps 和 Objects 的区别
增
map.set(‘t’,1)
set.add(item)
obj[‘t’]=1
查
map.has(‘t’)
set.has(a(被保存过的对象))
‘t’ in obj
改
map.set(‘t’,2)
item.t=2
obj[‘t’]=2;
删
map.delete(‘t’)
set.delete(item)
delete obj[t]
一个 Object 的键(key)只能是字符串或者 Symbols,但一个 Map 的键可以是任意值。
Map 中的键值是有序的(FIFO 原则),而添加到对象中的键则不是。
Map 的键值对个数可以从 size 属性获取,而 Object 的键值对个数只能手动计算。
Object 都有自己的原型,原型链上的键名有可能和你自己在对象上的设置的键名产生冲突。
如果对同一个键多次赋值,后面的值将覆盖前面的值。
注意,只有对同一个对象的引用,Map 结构才将其视为同一个键。这一点要非常小心。
const map = new Map();
map.set(['a'], 555);
map.get(['a']) // undefined
上面代码的set和get方法,表面是针对同一个键,但实际上这是两个值,内存地址是不一样的,因此get方法无法读取该键,返回undefined。
1.类型不同,weakSet只能存放对象
2.WeakSet 没有size属性,没有办法遍历它的成员。WeakSet 不能遍历,是因为成员都是弱引用,随时可能消失,遍历机制无法保证成员的存在。
3.foos对实例的引用,不会被计入内存回收机制,所以删除实例的时候,不用考虑foos,也不会出现内存泄漏。