手把手教你实现js中的Set类。😜
简介
Set
对象是值的集合,你可以按照插入的顺序迭代它的元素。 Set
中的元素只会出现一次,即 Set 中的元素是唯一的。
值的相等
1、Set
中的值总是唯一的, 所以需要判断两个值是否全等。
2、NaN
和undefined
都可以被存储在Set 中,NaN
之间被视为相同的值(尽管NaN !== NaN
)
使用
Set
实例
所有Set
实例继承自 Set.prototype
属性
Set.prototype.constructor
返回实例的构造函数。默认情况下是Set
。
Set.prototype.size
返回Set
对象的值的个数。
操作方法
Set.prototype.has(value)
返回一个布尔值,表示该值在Set中存在与否。
Set.prototype.add(value)
在Set
对象尾部添加一个元素。返回该Set
对象。
Set.prototype.delete(value)
移除Set
的中与这个值相等的元素,返回Set.prototype.has(value)
在这个操作前会返回的值(即如果该元素存在,返回true
,否则返回false
)。Set.prototype.has(value)
在此后会返回false
。
Set.prototype.clear()
移除Set
对象内的所有元素。
demo
let mySet = new Set()
mySet.add(0).add('0').add(null).add(undefined) // Set(4) {0, "0", null, undefined}
mySet.has('0') // true
mySet.has(1) // flase
mySet.has(null) // true
mySet.size // 4
mySet.delete(null) // true, null 从set中移除
mySet.has(null) // false
mySet.size // 3
console.log(mySet) // Set(4) {0, "0", undefined}
迭代方法
Set.prototype.keys()
返回一个新的迭代器对象,该对象包含Set
对象中的按插入顺序排列的所有元素的值。
Set.prototype.values()
返回一个新的迭代器对象,该对象包含Set
对象中的按插入顺序排列的所有元素的值。
Set.prototype.entries()
返回一个新的迭代器对象,该对象包含Set对象中的按插入顺序排列的所有元素的值的[value, value]数组。为了使这个方法和Map对象保持相似, 每个值的键和值相等。
Set.prototype.forEach(callbackFn[, thisArg])
按照插入顺序,为Set
对象中的每一个值调用一次callBackFn
。如果提供了thisArg
参数,回调中的this
会是这个参数。
demo
let mySet = new Set([0, '0', null, undefined])
mySet.keys() // SetIterator {0, "0", null, undefined}
mySet.values() // SetIterator {0, "0", null, undefined}
mySet.entries() // SetIterator {0, "0", null, undefined}
具体实现
在看具体实现前,先看下的工具方法
1、条件进行判断,抛出异常
const assert = (condition, msg) => {
if (!condition) throw new Error(msg)
}
2、isDef, 过滤掉null
和undefined
const isDef = (value) => {
return value != void 0
}
3、isIterable, 简单判断value是否是迭代器对象.
const isIterable = (value) => {
return isDef(value) && typeof value[Symbol.iterator] === 'function'
}
4、
function forOf(obj, cb) {
let iterable, result
if (typeof obj[Symbol.iterator] !== "function") throw new TypeError(obj + " is not iterable")
if (typeof cb !== "function") throw new TypeError('cb must be callable')
iterable = obj[Symbol.iterator]()
result = iterable.next()
while (!result.done) {
cb(result.value)
result = iterable.next()
}
}
源码
class Set {
constructor (iterable) {
this.value = []
assert(this instanceof Set, 'Constructor Set requires "new"') // 必须使用news来调用
data && data.forEach(function(item) {
this.add(item)
}, this)
}
get size() {
return this.value.length
}
has(value) {
return this.value.includes(value) // 使用includes方法判断是否包含 value MDN: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/includes
}
add(value) {
!this.has(value) && this.value.push(value) // value不存在则添加进数组
return this
}
delete(value) {
let result = this.has(value)
result && this.value.splice(this.value.indexOf(value), 1)
return result
}
clear() {
this.value = [] // 赋值一个空数组
}
// 返回一个迭代对象,该对象中的值是Set中的value
keys () {
return new Iterator(this.value)
}
values () {
return this.keys()
}
// 返回一个迭代对象,不同keys和values的是其值是[value, value]
entries () {
return new Iterator(this.value, (value) => [value, value])
}
// 返回一个新的迭代器对象,该对象包含Set对象中的按插入顺序排列的所有元素的值。
[Symbol.iterator] () {
return this.values()
}
}