Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
230 views
in Technique[技术] by (71.8m points)

javascript - 在JavaScript中模仿集合?(Mimicking sets in JavaScript?)

I'm working in JavaScript.

(我正在使用JavaScript。)

I'd like to store a list of unique , unordered string values, with the following properties:

(我想存储具有以下属性的唯一 ,无序字符串值的列表:)

  1. a fast way to ask 'is A in the list'?

    (快速询问“列表中是否有A”的方法?)

  2. a fast way to do 'delete A from the list if it exists in the list'

    (一种快速的方法(如果列表中存在A,则从列表中删除A))

  3. a fast way to do 'add A to the list if it is not already present'.

    (一种“将A添加到列表(如果尚不存在)的快速方法”。)

What I really want is a set.

(我真正想要的是一套。)

Any suggestions for the best way to mimic a set in JavaScript?

(有什么建议以最佳方式模仿JavaScript中的集合吗?)

This question recommends using an Object , with the keys storing properties, and the values all set to true: is that a sensible way?

(这个问题建议使用Object ,其键存储属性,并且所有值均设置为true:这是明智的方法吗?)

  ask by Richard translate from so

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

If you are programming in an ES6-capable environment (such as node.js, a specific browser with the ES6 capabilities you need or transpiling ES6 code for your environment), then you can use the Set object built into ES6 .

(如果您在支持ES6的环境中编程(例如,node.js,具有ES6功能的特定浏览器或为环境转换ES6代码),则可以使用ES6中内置Set对象 。)

It has very nice capabilities and can be used as is right in your environment.

(它具有非常好的功能,可以在您的环境中直接使用。)


For many simple things in an ES5 environment, using an Object works very well.

(对于ES5环境中的许多简单事物,使用Object效果很好。)

If obj is your object and A is a variable that has the value you want to operate on in the set, then you can do these:

(如果obj是您的对象,而A是具有要在集合中进行操作的值的变量,则可以执行以下操作:)

Initialization code:

(初始化代码:)

// create empty object
var obj = {};

// or create an object with some items already in it
var obj = {"1":true, "2":true, "3":true, "9":true};

Question 1: Is A in the list:

(问题1:列表中是否有A :)

if (A in obj) {
    // put code here
}

Question 2: Delete 'A' from the list if it's there:

(问题2:如果存在,请从列表中删除“ A”:)

delete obj[A];

Question 3: Add 'A' to the list if it wasn't already there

(问题3:如果尚未在列表中添加“ A”)

obj[A] = true;

For completeness, the test for whether A is in the list is a little safer with this:

(为了完整起见,使用以下方法测试A是否在列表中会更安全:)

if (Object.prototype.hasOwnProperty.call(obj, A))
    // put code here
}

because of potential conflict between built-in methods and/or properties on the base Object like the constructor property.

(因为基础对象上的内置方法和/或属性(例如constructor属性)之间可能存在冲突。)


Sidebar on ES6: The current working version of ECMAScript 6 or somethings called ES 2015 has a built-in Set object .

(ES6上的侧栏: ECMAScript 6或ES 2015的当前工作版本具有内置的Set对象 。)

It is implemented now in some browsers.

(现在已在某些浏览器中实现。)

Since browser availability changes over time, you can look at the line for Set in this ES6 compatibility table to see the current status for browser availability.

(由于浏览器可用性随时间变化,因此您可以在此ES6兼容性表中查看“ Set ”行,以查看浏览器可用性的当前状态。)

One advantage of the the built-in Set object is that it doesn't coerce all keys to a string like the Object does so you can have both 5 and "5" as separate keys.

(内置Set对象的一个??优点是,它不像Object那样将所有键都强制转换为字符串,因此您可以将5和“ 5”作为单独的键。)

And, you can even use Objects directly in the set without a string conversion.

(而且,您甚至可以直接在集合中使用对象,而无需进行字符串转换。)

Here's an article that describes some of the capabilities and MDN's documentation on the Set object.

(本文介绍了Set对象上的一些功能和MDN文档 。)

I have now written a polyfill for the ES6 set object so you could start using that now and it will automatically defer to the built-in set object if the browser supports it.

(我现在为ES6设置对象编写了一个polyfill,因此您现在就可以开始使用它,如果浏览器支持,它将自动遵从内置设置对象。)

This has the advantage that you're writing ES6 compatible code that will work all the way back to IE7.

(这样做的好处是您正在编写与ES6兼容的代码,这些代码将一直使用到IE7。)

But, there are some downsides.

(但是,还有一些缺点。)

The ES6 set interface takes advantage of the ES6 iterators so you can do things like for (item of mySet) and it will automatically iterate through the set for you.

(ES6集合接口利用了ES6迭代器,因此您可以执行for (item of mySet) ,并且它将自动为您迭代集合。)

But, this type of language feature cannot be implemented via polyfill.

(但是,这种语言功能无法通过polyfill实现。)

You can still iterate an ES6 set without using the new ES6 languages features, but frankly without the new language features, it isn't as convenient as the other set interface I include below.

(您仍然可以在不使用新ES6语言功能的情况下迭代ES6集,但是坦率地说,在没有新语言功能的情况下,它不如我在下面包括的其他集界面那么方便。)

You can decide which one works best for you after looking at both.

(查看两者后,您可以决定哪个最适合您。)

The ES6 set polyfill is here: https://github.com/jfriend00/ES6-Set .

(ES6集合polyfill在这里: https : //github.com/jfriend00/ES6-Set 。)

FYI, in my own testing, I've noticed that the Firefox v29 Set implementation is not fully up-to-date on the current draft of the spec.

(仅供参考,在我自己的测试中,我注意到Firefox v29 Set实施不是最新的规范草案。)

For example, you can't chain .add() method calls like the spec describes and my polyfill supports.

(例如,您不能像规范说明和我的polyfill支持那样链接.add()方法调用。)

This is probably a matter of a specification in motion as it is not yet finalized.

(这可能是运动规范的问题,因为它尚未最终确定。)


Pre-Built Set objects: If you want an already built object that has methods for operating on a set that you can use in any browser, you can use a series of different pre-built objects that implement different types of sets.

(预先构建的Set对象:如果希望已经构建的对象具有可在任何浏览器中使用的对集合进行操作的方法,则可以使用实现不同类型集合的一系列不同的预先构建的对象。)

There is a miniSet which is small code that implements the basics of a set object.

(有一个miniSet,它是一些小代码,可实现set对象的基础。)

It also has a more feature rich set object and several derivations including a Dictionary (let's you store/retrieve a value for each key) and an ObjectSet (let's you keep a set of objects - either JS objects or DOM objects where you either supply the function that generates a unique key for each one or the ObjectSet will generate the key for you).

(它还具有功能更丰富的set对象和多个派生对象,包括Dictionary(让您为每个键存储/获取一个值)和ObjectSet(让您保留一组对象-JS对象或DOM对象,您可以在其中提供为每个键生成唯一键的函数,否则ObjectSet会为您生成键)。)

Here's a copy of the code for the miniSet (most up-to-date code is here on github ).

(这是miniSet的代码副本(最新代码在github上 )。)

"use strict";
//-------------------------------------------
// Simple implementation of a Set in javascript
//
// Supports any element type that can uniquely be identified
//    with its string conversion (e.g. toString() operator).
// This includes strings, numbers, dates, etc...
// It does not include objects or arrays though
//    one could implement a toString() operator
//    on an object that would uniquely identify
//    the object.
// 
// Uses a javascript object to hold the Set
//
// This is a subset of the Set object designed to be smaller and faster, but
// not as extensible.  This implementation should not be mixed with the Set object
// as in don't pass a miniSet to a Set constructor or vice versa.  Both can exist and be
// used separately in the same project, though if you want the features of the other
// sets, then you should probably just include them and not include miniSet as it's
// really designed for someone who just wants the smallest amount of code to get
// a Set interface.
//
// s.add(key)                      // adds a key to the Set (if it doesn't already exist)
// s.add(key1, key2, key3)         // adds multiple keys
// s.add([key1, key2, key3])       // adds multiple keys
// s.add(otherSet)                 // adds another Set to this Set
// s.add(arrayLikeObject)          // adds anything that a subclass returns true on _isPseudoArray()
// s.remove(key)                   // removes a key from the Set
// s.remove(["a", "b"]);           // removes all keys in the passed in array
// s.remove("a", "b", ["first", "second"]);   // removes all keys specified
// s.has(key)                      // returns true/false if key exists in the Set
// s.isEmpty()                     // returns true/false for whether Set is empty
// s.keys()                        // returns an array of keys in the Set
// s.clear()                       // clears all data from the Set
// s.each(fn)                      // iterate over all items in the Set (return this for method chaining)
//
// All methods return the object for use in chaining except when the point
// of the method is to return a specific value (such as .keys() or .isEmpty())
//-------------------------------------------


// polyfill for Array.isArray
if(!Array.isArray) {
    Array.isArray = function (vArg) {
        return Object.prototype.toString.call(vArg) === "[object Array]";
    };
}

function MiniSet(initialData) {
    // Usage:
    // new MiniSet()
    // new MiniSet(1,2,3,4,5)
    // new MiniSet(["1", "2", "3", "4", "5"])
    // new MiniSet(otherSet)
    // new MiniSet(otherSet1, otherSet2, ...)
    this.data = {};
    this.add.apply(this, arguments);
}

MiniSet.prototype = {
    // usage:
    // add(key)
    // add([key1, key2, key3])
    // add(otherSet)
    // add(key1, [key2, key3, key4], otherSet)
    // add supports the EXACT same arguments as the constructor
    add: function() {
        var key;
        for (var i = 0; i < arguments.length; i++) {
            key = arguments[i];
            if (Array.isArray(key)) {
                for (var j = 0; j < key.length; j++) {
                    this.data[key[j]

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...