在Eloquent JavaScript,第4章中,通过创建对象并将值存储为属性名称,然后将任意值(例如true)分配为属性值来创建一组值。要检查该值是否已包含在集合中,请使用in
运算符:
var set = {};
if (!'Tom' in set) {
set.Tom = true;
}
这是惯用的JavaScript吗?会不会使用更好的数组?
var set = [];
if (!'Tom' in set) {
set.push = 'Tom';
}
在Eloquent JavaScript,第4章中,通过创建对象并将值存储为属性名称,然后将任意值(例如true)分配为属性值来创建一组值。要检查该值是否已包含在集合中,请使用in
运算符:
var set = {};
if (!'Tom' in set) {
set.Tom = true;
}
这是惯用的JavaScript吗?会不会使用更好的数组?
var set = [];
if (!'Tom' in set) {
set.push = 'Tom';
}
if(!('Tom' in set))
。目前表示false in set
自!'Tom' === false
。
Answers:
集合现在在ES2015中可用(又名ES6,即ECMAScript 6)。自2015年6月起,ES6已成为JavaScript的当前标准。
ECMAScript 6具有数据结构Set,该数据结构适用于任意值,快速且可以正确处理NaN。-阿克塞尔Rauschmayer先生,探索ES6
Axel Rauschmayer的书Exploring ES6的前两个示例:
管理单个元素:
> let set = new Set();
> set.add('red')
> set.has('red')
true
> set.delete('red')
true
> set.has('red')
false
确定集合的大小并清除它:
> let set = new Set();
> set.add('red')
> set.add('green')
> set.size
2
> set.clear();
> set.size
0
如果您想了解有关JavaScript中的Set的更多信息,请查看Exploring ES6。这本书是可以在线免费阅读的,但是如果您想支持作者Axel Rauschmayer博士,则可以30美元左右的价格购买该书。
如果现在要使用Sets和ES6 ,则可以使用Babel,ES6到ES5编译器及其polyfills。
编辑:截至2017年6月6日,大多数主要浏览器在其最新版本(IE 11除外)中都具有完整的Set支持。这意味着如果您不希望支持较旧的浏览器,则可能不需要Babel。如果要查看包括当前浏览器在内的其他浏览器的兼容性,请查看Kangax的ES6兼容性表。
编辑:
只是澄清初始化。集可以在其构造函数中采用任何同步迭代。这意味着它们不仅可以接受数组,还可以接受字符串和迭代器。例如,以下一组数组和字符串初始化:
const set1 = new Set(['a','a','b','b','c','c']);
console.log(...set1);
console.log(set1.size);
const set2 = new Set("aabbcc");
console.log(...set2);
console.log(set2.size);
数组和字符串的两个输出是相同的。注意,这...set1
是传播语法。似乎将iterable的每个元素都逐一添加到集合中,因此,由于数组和字符串具有相同的元素,并且由于元素的顺序相同,因此创建的集合也相同。关于集合要注意的另一件事是,在对它们进行迭代时,迭代顺序遵循将元素插入到集合中的顺序。这是一个遍历集合的示例:
const set1 = new Set(['a','a','b','b','c','c']);
for(const element of set1) {
console.log(element);
}
由于您可以使用任何可迭代的方法来初始化集合,因此甚至可以使用生成器函数中的迭代器。这是两个产生相同输出的迭代器初始化的示例:
// a simple generator example
function* getLetters1 () {
yield 'a';
yield 'a';
yield 'b';
yield 'b';
yield 'c';
yield 'c';
}
// a somewhat more commonplace generator example
// with the same output as getLetters1.
function* getLetters2 (letters, repeatTimes) {
for(const letter of letters) {
for(let i = 0; i < repeatTimes; ++i) {
yield letter;
}
}
}
console.log("------ getLetters1 ------");
console.log(...getLetters1());
const set3 = new Set(getLetters1());
console.log(...set3);
console.log(set3.size);
console.log("------ getLetters2 ------");
console.log(...getLetters2('abc', 2));
const set4 = new Set(getLetters2('abc', 2));
console.log(...set4);
console.log(set4.size);
这些示例的生成器函数可以写为不重复,但是如果生成器函数更复杂,并且只要以下内容不会对性能产生负面影响,则可以使用Set方法帮助仅从生成器的值中获取不再重复。
如果您想了解更多有关集合的知识,而无需阅读Rauschmayer博士在其书中的章节,则可以查看Set上的MDN文档。MDN还具有在一组迭代的更多的例子,例如使用forEach
和使用.keys
,.values
以及.entries
方法。MDN还具有示例,例如集合并集,集合相交,集合差,对称集合差和集合超集检查。希望其中的大多数操作都可以在JavaScript中使用,而无需构建自己的函数来支持它们。实际上,这个TC39提案提出了新的Set方法,如果该提案达到了第4阶段,则应该在将来的某个时间点将以下方法添加到JavaScript中的Set中:
- Set.prototype.intersection(iterable)-方法通过设置交集操作创建新的Set实例。
- Set.prototype.union(iterable)-方法通过集合联合操作创建新的Set实例。
- Set.prototype.difference(iterable)-方法创建新的Set,而iterable中没有元素。
- Set.prototype.symmetricDifference(iterable)-返回仅在this或inerable中找到的元素集。
- Set.prototype.isSubsetOf(iterable)
- Set.prototype.isDisjointFrom(iterable)
- Set.prototype.isSupersetOf(可迭代)
我使用dict对象作为集合。这适用于字符串和数字,但是如果您想使用自定义相等和比较运算符来拥有一组对象,我想会引起问题:
创建集合:
var example_set =
{
'a':true,
'b':true,
'c':true
}
测试是否包含在集合中
if( example_set['a'] ){
alert('"a" is in set');
}
向集合添加元素
example_set['d'] = true;
从集合中删除元素
delete example_set['a']
;
Set
。这有帮助。
第一种方法是惯用JavaScript。
每当您要存储键/值对时,都必须使用JavaScript对象。至于数组,有几个问题:
索引是数值。
没有简单的方法来检查值是否在数组中而不循环。
一组不允许重复。数组可以。
如果要从数组创建集合,只需执行以下操作:
let arr = [1, 1, 2, 1, 3];
let mySet = new Set(arr); // Set { 1, 2, 3 }
这是我在Python编程时非常喜欢的一种糖语法,很高兴ES6最终使做相同的事情成为可能。
注意:然后我意识到我说的话并没有直接回答您的问题。在ES5中出现这种“ hack”的原因是因为通过键在对象中的查找时间(O(1))比在数组(O(n))中的查找时间明显更快。在对性能至关重要的应用程序中,您可以牺牲一点可读性或直觉来获得更好的性能。
但是,欢迎来到2017年,您现在可以在所有主流现代浏览器中使用适当的Set!
ES6
/中设置ES2015
:ES6
/ES2015
现在已经内置了。集合是一种数据结构,它允许存储任何类型的唯一值,无论是原始值还是对象引用。可以使用ES6
内置set构造函数以以下方式声明一个set :
const set = new Set([1, 2, 3, 4, 5]);
使用Set构造函数创建集合时,我们新创建的set对象将从继承Set.prototype
。这具有各种辅助方法和属性。这使您可以轻松地执行以下操作:
const set = new Set([1, 2, 3, 4, 5]);
// checkout the size of the set
console.log('size is: ' + set.size);
// has method returns a boolean, true if the item is in the set
console.log(set.has(1));
// add a number
set.add(6);
// delete a number
set.delete(1);
// iterate over each element using a callback
set.forEach((el) => {
console.log(el);
});
// remove all the entries from the set
set.clear();
除了缺少某些功能的IE之外,所有主流浏览器现在都完全支持集。有关确切的参考,请参阅mdn docs。
let mySet = new Set()
mySet.add(2) // Set {2}
mySet.add(7) // Set {2, 7}
mySet.add(7) // Set {2, 7}
mySet.add('my text') // Set {2, 7, 'my text'}
let myObj = { a: 1, b: 2 }
mySet.add(myObj) // Set {2, 7, 'my text', {...}}
mySet.has(2) // true
mySet.has(myObj) // true
mySet.size // 4
迭代
for (let item of mySet) console.log(item) // 2, 7, 'my text', {a:1, b:2}
mySet.forEach(value => console.log(value)) // 2, 7, 'my text', {a:1, b:2}
转换为数组
var myArr = Array.from(mySet) // [2, 7, 'my text', {a:1, b:2}]
Set Set提供的最独特的功能是Set对象中的每个值都必须是唯一的。因此,您不能添加重复的值。
'Tom' in set
看起来像真的数组?看起来很像你对某件事有错误的假设,我正在试图找出什么。