ES6在处理对象上,又添加了新方法。
1. 属性简洁写法
当属性名和属性值变量同名时,ES6允许在对象中只写属性名,不写属性。
关键点有两个:
- 属性值为变量
- 属性值变量名==属性名
例如:
var foo = "abc";
var obj = {
name: 'nicole',
foo
}; //相当于是 var obj = {foo: foo}
如果属性值是函数,可以省略关键字function
,如下:
var obj = {
say(name) {
return "hello, " + name;
}
}
//等价于
var obj = {
say: function (name) {
return "hello, " + name;
}
}
2. 属性名表达式
ES5中,使用字面量方式定义对象时,属性名不能是变量。ES6中可以支持变量/表达式格式的属性名,格式为[propertyName]
。
var key = "property name";
var a = "hello";
var b = "world";
var obj = {
[key]: 1,
name: "nicole",
[a+" "+b]: "good"
};
obj["property name"]; //1
obj["hello world"]; //"good"
注意:“属性简洁写法”和“属性名表达式”不能同时使用。
3. Object.is()
Object.is(val1, val2)
用于判断两个值是否严格相等,用===
判断。
注意:我们知道NaN===NaN
会返回false
,但是Object.is(NaN, NaN)
,返回true
。
4. Object.assign()
Object.assign(target, object1 [,objectN])
用于对象拷贝,将对象object1...
复制到对象target
中。
Object.assign()
是浅拷贝,类似jQuery.extend( false, target, object1 [, objectN ] )
。
var obj1 = {a: {b:1}, x: 1};
var obj2 = {x: 3, y: 4};
var target = {};
Object.assign(target, obj1, obj2);
// 改变复制源对象的值
obj1.a.b = 11;
// 复制对象同步改变,说明复制的仅仅是源对象引用地址
console.log(target); // { a: { b: 11 }, x: 3, y: 4 }
5. WeakMap和WeakSet
Map
和Set
是对对象的增强类型,Map
偏向对象增强,Set
偏向数组增强。
Map
和Object
最大的区别,就是Map
的Key可以不是简单类型,比如,对象作为Key。并且,Map
和Set
内置很多方法来管理和操作数据集合,比如:has
, add
, delete
, clear
等。
WeakSet
结构与Set
类似,也是不重复的值的集合,特点如下:
- 成员只能是对象
-
WeakSet
中的对象都是弱引用
,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于WeakSet之中。
同样的,WeakMap结构与Map结构基本类似,特点如下:
- 只接受对象作为键名(null除外),
-
WeakMap
中的对象都是弱引用
在计算机程序设计中,弱引用与强引用相对,是指不能确保其引用的对象不会被垃圾回收器回收的引用。 一个对象若只被弱引用所引用,则被认为是不可访问(或弱可访问)的,并因此可能在任何时刻被回收。
举个例子,如下两个对象elt1和elt2, 哪怕已经销毁了,由于array强引用了它们,否则垃圾回收机制不会释放elt1和elt2的内存。除非手动去掉引用:array[0]=null; array[1]=null;
const elt1 = document.getElementById("id1");
const elt2 = document.getElementById("id2");
const array = [elt1, elt2]
下面看看两种类型的使用场景,就更能了解了。
WeakSet
- 定义类
const requests = new WeakSet();
class ApiRequest {
constructor() {
requests.add(this);
}
makeRequest() {
if(!request.has(this)) throw new Error("Invalid access");
// do work
}
}
- 创建DOM(通过加入对应集合,给这个节点打上“禁用”标签,只要 WeakSet 中任何元素从 DOM 树中被删除,垃圾回收程序就可以忽略其存在,而立即释放其内存)
const disabledElements = new WeakSet();
const loginButton = document.querySelector('#login');
WeakMap
- 注册监听事件的listener对象(由于监听函数是放在 WeakMap 里面,则一旦dom对象ele1,ele2消失,与它绑定的监听函数handler1和handler2 也会自动消失)
// 代码1
ele1.addEventListener('click', handler1, false);
ele2.addEventListener('click', handler2, false);
// 代码2
const listener = new WeakMap();
listener.set(ele1, handler1);
listener.set(ele2, handler2);
ele1.addEventListener('click', listener.get(ele1), false);
ele2.addEventListener('click', listener.get(ele2), false);
- 部署私有属性(Countdown类的两个内部属性
_counter
和_action
,是实例的弱引用,所以如果删除实例,它们也就随之消失,不会造成内存泄漏。)
let _counter = new WeakMap();
let _action = new WeakMap();
class Countdown {
constructor(counter, action) {
_counter.set(this, counter);
_action.set(this, action);
}
dec() {
let counter = _counter.get(this);
if (counter < 1) return;
counter--;
_counter.set(this, counter);
if (counter === 0) {
_action.get(this)();
}
}
}
let c = new Countdown(2, () => console.log('DONE'));
c.dec()
c.dec()
- 数据缓存(当我们需要在不修改原有对象的情况下储存某些属性等,而又不想管理这些数据时,可以使用WeakMap)
const cache = new WeakMap();
function countOwnKeys(obj) {
if (cache.has(obj)) {
return cache.get(obj)
}
else {
const count = Object.keys(obj).length
cache.set(obj, count)
return count
}
}
小结
最常用的是“属性简洁写法”和“属性名表达式”。
做对象拷贝时,除了Object.assign()
,更简便的方法是使用“扩展运算符”(参考上一节文章ECMAScript6基础学习教程(四)函数 - 扩展运算符)。
例子如下:
var obj1 = {a: {b:1}, x: 1};
var obj2 = {x: 3, y: 4};
var target = {...obj1, ...obj2};
// 改变复制源对象的值
obj1.a.b = 11;
// 复制对象同步改变
console.log(target); // { a: { b: 11 }, x: 3, y: 4 }