资讯专栏INFORMATION COLUMN

ES6学习(三)之Set的模拟实现

余学文 / 3455人阅读

摘要:注意这里因为添加完元素之后返回的是该对象,所以可以链式调用结果是,但是中只会存一个模拟实现的整体结构除此之外我们还需要二个辅助方法模拟行为对迭代器对象进行遍历操作。

更多系列文章请看

在实现之前我们可以通过阮一峰的ECMAScript 6 入门了解一下Set的基本信息

1、Set的基本语法
new Set([ iterable ])

可以传递一个可迭代对象,它的所有元素将被添加到新的 Set中。如果不指定此参数或其值为null,则新的 Set为空。

let s = new Set([ 1, 2, 3 ]) // Set(3) {1, 2, 3}
let s2 = new Set() // Set(0) {}
let s3 = new Set(null /* or undefined */) // Set(0) {}
1.1 实例属性和方法

属性

constructor: Set的构造函数

size: Set 长度

操作方法

add(value):在Set对象尾部添加一个元素。返回该Set对象。

has(value):返回一个布尔值,表示该值在Set中存在与否。

delete(value):移除Set中与这个值相等的元素,返回has(value)在这个操作前会返回的值(即如果该元素存在,返回true,否则返回false)

-clear():移除Set对象内的所有元素。没有返回值

遍历方法

keys():返回一个新的迭代器对象,该对象包含Set对象中的按插入顺序排列的所有元素的值。

-values():返回一个新的迭代器对象,该对象包含Set对象中的按插入顺序排列的所有元素的值。

entries():返回一个新的迭代器对象,该对象包含Set对象中的按插入顺序排列的所有元素的值的[value, value]数组。为了使这个方法和Map对象保持相似, 每个值的键和值相等。

-forEach(callbackFn[, thisArg]):按照插入顺序,为Set对象中的每一个值调用一次callBackFn。如果提供了thisArg参数,回调中的this会是这个参数。

let s = new Set()

s.add(1) // Set(1) {1}
  .add(2) // Set(2) {1, 2}
  .add(NaN) // Set(2) {1, 2, NaN}
  .add(NaN) // Set(2) {1, 2, NaN}

// 注意这里因为添加完元素之后返回的是该Set对象,所以可以链式调用
// NaN === NaN 结果是false,但是Set中只会存一个NaN

s.has(1) // true
s.has(NaN) // true

s.size // 3

s.delete(1)
s.has(1) // false
s.size // 2

s.clear()

s // Set(0) {}

let s2 = new Set([ "s", "e", "t" ])

s2 // SetIterator {"s", "e", "t"}
s2.keys() // SetIterator {"s", "e", "t"}
s2.values() // SetIterator {"s", "e", "t"}
s2.entries() // SetIterator {"s", "e", "t"}

// log
[ ...s2 ] // ["s", "e", "t"]
[ ...s2.keys() ] //  ["s", "e", "t"]
[ ...s2.values() ] //  ["s", "e", "t"]
[ ...s2.entries() ] //  [["s", "s"], ["e", "e"], ["t", "t"]]

s2.forEach(function (value, key, set) {
  console.log(value, key, set, this)
})

// s s Set(3) {"s", "e", "t"} Window
// e e Set(3) {"s", "e", "t"} Window
// t t Set(3) {"s", "e", "t"} Window

s2.forEach(function () {
  console.log(this)
}, { name: "qianlongo" })

// {name: "qianlongo"}
// {name: "qianlongo"}
// {name: "qianlongo"}

for (let value of s2) {
  console.log(value)
}
// s
// e
// t

for (let value of s2.entries()) {
  console.log(value)
}
// ["s", "s"]
// ["e", "e"]
// ["t", "t"]
2、模拟实现 2.1、Set的整体结构
class Set {

  constructor (iterable) {}

  get size () {}

  has () {}

  add () {}

  delete () {}  

  clear () {}

  forEach () {}

  keys () {}

  values () {}  

  entries () {}

  [ Symbol.iterator ] () {}
}

除此之外我们还需要二个辅助方法
1、forOf,模拟for of行为, 对迭代器对象进行遍历操作。

const forOf = (iterable, callback, ctx) => {
  let result
  iterable = iterable[ Symbol.iterator ]()
  result = iterable.next()

  while (!result.done) {
    callback.call(ctx, result.value)
    result = iterable.next()
  }
}

2、Iterator迭代器,更多迭代器信息请看Iterator,我们这里面用迭代器是为了让我们的set的values()等可进行遍历。

class Iterator {
    constructor (arrayLike, iteratee = (value) => value) {
      this.value = Array.from(arrayLike)
      this.nextIndex = 0
      this.len = this.value.length
      this.iteratee = iteratee
    }
  
    next () {
      let done = this.nextIndex >= this.len
      let value = done ? undefined : this.iteratee(this.value[ this.nextIndex++ ])
  
      return { done, value }
    }
  
    [ Symbol.iterator ] () {
      return this
    }
  }
2.3、实现源码
class Set {
    constructor(iterable){
        this.value = [];
        if(!this instanceof Set) throw new Error("Constructor Set requires "new"");
        if(isDef(iterable)) {
            if(typeof iterable[ Symbol.iterator ] !== "function") new Error(`${iterable} is not iterable`);
            // 循环可迭代对象,初始化
            forOf(iterable, value => this.add(value));
        }
    }

    get size(){
        return this.value.length;
    }
    
    has(val) {
        return this.value.includes(val); // [ NaN ].includes(NaN)会返回true,正好Set也只能存一个NaN
    }
    add(val) {
        if(!this.has(val)) {
            this.value.push(val);
        }
        return this;
    }
    delete(val) {
        const index = this.value.indexOf(val);
        if (index > -1) {
            this.value.splice(index, 1);
            return true;
        }
        return false;
    }
    clear() {
        this.value.length = 0;
    }
    forEach(cb, arg) {
        forOf(this.values(), val => {
            cb.call(arg, val, val, this);
        })
    }
    keys() {
        return new Iterator(this.value);
    }

    values() {
        return this.keys();
    }
    entries() {
        return new Iterator(this.value, (value) => [ value, value ])
    }
    [Symbol.iterable]() {
        return this.values();
    }
}
模拟过程中可能会有相应的错误,也不是和原生的实现完全一致。仅当学习之用.

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/102925.html

相关文章

  • ES6 系列模拟实现一个 Set 数据结构

    摘要:基本介绍提供了新的数据结构。初始化本身是一个构造函数,用来生成数据结构。函数可以接受一个数组或者具有接口的其他数据结构作为参数,用来初始化。返回一个布尔值,表示该值是否为的成员。清除所有成员,无返回值。 基本介绍 ES6 提供了新的数据结构 Set。 它类似于数组,但是成员的值都是唯一的,没有重复的值。 初始化 Set 本身是一个构造函数,用来生成 Set 数据结构。 let set ...

    Backache 评论0 收藏0
  • 从零到有模拟实现一个Set

    摘要:过滤掉和简单判断是否是迭代器对象模拟行为对迭代器对象进行遍历操作。看到这里你可能已经知道了,要实现的功能之一就是提供一个迭代器。原文链接参考迭代器和生成器系列之模拟实现一个数据结构展开语法循环 前言 es6新增了Set数据结构,它允许你存储任何类型的唯一值,无论是原始值还是对象引用。这篇文章希望通过模拟实现一个Set来增加对它的理解。 原文链接 用在前面 实际工作和学习过程中,你可能也...

    PAMPANG 评论0 收藏0
  • 箭头函数你想知道都在这里

    摘要:没有箭头函数没有自己的对象,这不一定是件坏事,因为箭头函数可以访问外围函数的对象那如果我们就是要访问箭头函数的参数呢你可以通过命名参数或者参数的形式访问参数不能通过关键字调用函数有两个内部方法和。 1、基本语法回顾 我们先来回顾下箭头函数的基本语法。ES6 增加了箭头函数: var f = v => v; // 等同于 var f = function (v) { return ...

    xiaoqibTn 评论0 收藏0
  • ES6】更易于继承类语法

    摘要:的类使用熟悉的关键字指定类继承的函数,并且可以通过方法访问父类的构造函数。例如继承一个的类继承了,术语上称为基类,为派生类。例如注意到上例中,不仅是派生类的实例,也是派生类的实例,内建对象继承的实用之处是改变返回对象的类型。 和其它面向对象编程语言一样,ES6 正式定义了 class 类以及 extend 继承语法糖,并且支持静态、派生、抽象、迭代、单例等,而且根据 ES6 的新特性衍...

    Lionad-Morotar 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<