1.Set和Map数据结构
a.Set结构
Set结构类似数组,但是成员是唯一的,不可重复。
Set本身是一个构造函数,用来生成Set数据结构,Set函数可以接受数组或类数组对象作为参数。
//参数是数组
var set = new Set([1, 2, 3, 4, 4]);
[...set]
// [1, 2, 3, 4]
var items = new Set([1, 2, 3, 4, 5, 5, 5, 5]);
items.size // 5
//参数是类数组对象
function divs () {
return [...document.querySelectorAll('div')];
}
var set = new Set(divs());
set.size // 56
Set可以用来数组去重 [...new Set(array)]
向Set加入值时不会做类型转换,在加入值时,Set判断两值是否相等是通过===
判断。
Set实例的方法:
- add(value)
向Set结构添加值,返回实例本身,所以可以链式调用。
let a = new Set();
a.add(1).add(2).add(3);
delete(value)
删除实例中的某个值,返回布尔值,表明成功或失败。has(value)
检验某个值是否是实例的成员,并返回布尔值。clear()
清空实例中的所有成员,没有返回值。
Array.from()可以将Set结构转换为数组
var items = new Set([1, 2, 3, 4, 5]);
var array = Array.from(items);
array;
//[1,2,3,4,5]
数组去重:
function dedupe(array) {
return Array.from(new Set(array));
}
dedupe([1, 1, 2, 3]) // [1, 2, 3]
Set的遍历:(Set结构中键名和键值是同一个值 )
let set = new Set(['red', 'green', 'blue']);
for (let item of set.keys()) {
console.log(item);
}
// red
// green
// blue
for (let item of set.values()) {
console.log(item);
}
// red
// green
// blue
for (let item of set.entries()) {
console.log(item);
}
// ["red", "red"]
// ["green", "green"]
// ["blue", "blue"]
b.WeakSet
WeakSet结构与Set结构类似,但是WeakSet的成员只能是对象(数组或类数组对象等)。当WeakSet参数是数组时,数组成员则会成为WeakSet的成员,如果数组成员不是对象则会报错。
var b = [3, 4];
var ws = new WeakSet(b);
// Uncaught TypeError: Invalid value used in weak set(…)
var a = [[1,2], [3,4]];
var ws = new WeakSet(a);
WeakSet没有size属性,不可遍历。
c.Map结构
Map结构类似javascript中的对象,但是Map结构中的“键”的范围不仅限于字符串,各种类型的值都可以当做键。Map的参数可以是一个数组,数组的成员是表示键值对的数组。
var map = new Map([['name', '张三'], ['title', 'Author']]);
map.size // 2
map.has('name') // true
map.get('name') // "张三"
map.has('title') // true
map.get('title') // "Author"
如果对同一个键多次赋值,后面的值将取代前面的值。
只有对同一个对象的引用,Map结构才将其视为同一个键。
var map = new Map();
map.set(['a'], 555);
map.get(['a']) // undefined
var a={};
map.set(a,10);
map.get(a); // 10
Map实例的方法
- set(key, value)
设置键key所对应的值value,如果key存在则更新值,如果不存在则新增。key可以是任意类型。 - get(key)
读取键key对应的值,找不到key时返回undefined。 - has(key)
检验某个键key是都在Map实例中,返回布尔值。 - delete(key)
删除某个键,返回true。如果删除失败,返回false。 - clear()
清楚实例中的所有成员。
Map的遍历:
let map = new Map([
['F', 'no'],
['T', 'yes'],
]);
for (let key of map.keys()) {
console.log(key);
}
// "F"
// "T"
for (let value of map.values()) {
console.log(value);
}
// "no"
// "yes"
for (let item of map.entries()) {
console.log(item[0], item[1]);
}
// "F" "no"
// "T" "yes"
//等同于
for (let [key, value] of map) {
console.log(key, value);
}
d.WeakMap
WeakMap与Map结构类似,但是只接受对象作为键名(null除外),不接受其他类型的值作为键名,而且键名所指向的对象,不计入垃圾回收机制。
WeakMap的典型应用就是DOM节点作为键名。
let myElement = document.getElementById('logo');
let myWeakmap = new WeakMap();
myWeakmap.set(myElement, {timesClicked: 0});
myElement.addEventListener('click', function() {
let logoData = myWeakmap.get(myElement);
logoData.timesClicked++;
myWeakmap.set(myElement, logoData);
}, false);
myElement是一个DOM节点,每当发生click事件,就更新一下状态。一旦这个DOM节点删除,该状态就会自动消失,不存在内存泄漏风险。
2.Class
ES6新增了类,作为对象的模板
//定义类
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
上例中,constructor方法是构造方法,是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,如果没有显式定义,会默认添加一个空的constructor方法。
类的实例通过new
调用,没有new
则会报错。
var point = new Point(1,2);
类也可以通过类表达式来定义:
let Point = class {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
实例的属性除非显式定义在其本身(即定义在this对象上),否则都是定义在原型上(即定义在class上)。
Class没有变量提升(无论是类声明还是类表达式声明),调用时必须在声明之后。
new Foo(); // ReferenceError
class Foo {}
Class的继承
Class之间可以通过extends
关键字实现继承,通过super
来调用父类
class ColorPoint extends Point {
constructor(x, y, color) {
super(x, y); // 调用父类的constructor(x, y)
this.color = color;
}
toString() {
return this.color + ' ' + super.toString(); // 调用父类的toString()
}
}
var a = new ColorPoint(1,2,'blue');
a.toString(); // "blue (1, 2)"
super
表示父类的构造函数,用来新建父类的this对象。子类必须在constructor方法中调用super
方法,否则新建实例时会报错。因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super
方法,子类就得不到this对象。并且只有调用super
之后,才可以使用this关键字,否则会报错。
getter和setter
class ColorPoint extends Point {
constructor(x, y, color) {
super(x, y);
this.color = color;
}
get color(){
return this._color.toUpperCase;
}
set color(color){
this._color=color;
}
toString() {
return this.color + ' ' + super.toString();
}
}
var c = new colorPoint(1,2,'blue');
c.color; // "BLUE"
c._color; // "blue"
实例在设置color属性时也设置了_color属性,同时也将color属性变成了大写。
静态方法
类相当于实例的原型,所有在类中定义的方法,都会被实例继承。但是类的静态方法不会被实例继承,只能通过类来调用。静态方法需要 static
关键字
class ColorPoint extends Point {
constructor(x, y, color) {
super(x, y);
this.color = color;
}
toString() {
return this.color + ' ' + super.toString();
}
static showColor(){
return "color";
}
}
ColorPoint.showColor(); // "color"
父类的静态方法可以被子类继承。子类可以通过super
调用父类的静态方法。
参考资料:《ECMAScript 6 入门》——阮一峰