diff --git a/CHANGELOG.md b/CHANGELOG.md index 68a78332ae51..b1184ccab4a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## Changelog ##### Unreleased +- [`Array` grouping proposal](https://github.com/tc39/proposal-array-grouping): + - Moved to the stage 2 + - Added `Array.prototype.groupByMap` method + - Removed `@@species` support - Added [change `Array` by copy stage 2 proposal](https://github.com/tc39/proposal-change-array-by-copy): - `Array.prototype.toReversed` - `Array.prototype.toSorted` diff --git a/README.md b/README.md index da08e9577990..5ab80b47b4cd 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,7 @@ Promise.resolve(32).then(x => console.log(x)); // => 32 - [`Iterator` helpers](#iterator-helpers) - [New `Set` methods](#new-set-methods) - [`Map.prototype.emplace`](#mapprototypeemplace) + - [`Array` grouping](#array-grouping) - [Change `Array` by copy](#change-array-by-copy) - [`Array.isTemplateObject`](#arrayistemplateobject) - [`Symbol.{ asyncDispose, dispose }` for `using` statement](#symbol-asyncdispose-dispose--for-using-statement) @@ -112,7 +113,6 @@ Promise.resolve(32).then(x => console.log(x)); // => 32 - [`compositeKey` and `compositeSymbol`](#compositekey-and-compositesymbol) - [`Array.fromAsync`](#arrayfromasync) - [`Array` filtering](#array-filtering) - - [`Array` grouping](#array-grouping) - [`Array` deduplication](#array-deduplication) - [Getting last item from `Array`](#getting-last-item-from-array) - [`Number.range`](#numberrange) @@ -2353,21 +2353,16 @@ console.log(compositeSymbol(1, a, 2, b) === compositeSymbol(1, a, 2, b)); // => console.log(compositeSymbol(a, a) === compositeSymbol(a, a)); // => true ``` ##### [`Array.fromAsync`](https://github.com/tc39/proposal-array-from-async)[⬆](#index) -Modules [`esnext.array.from-async`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.array.from-async.js) and [`esnext.typed-array.from-async`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.typed-array.from-async.js) +Modules [`esnext.array.from-async`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.array.from-async.js). ```js class Array { static fromAsync(asyncItems: AsyncIterable | Iterable | ArrayLike, mapfn?: (value: any, index: number) => any, thisArg?: any): Array; } - -class %TypedArray% { - static fromAsync(asyncItems: AsyncIterable | Iterable | ArrayLike, mapfn?: (value: number, index: number, target) => number, thisArg?: any): %TypedArray%; -} ``` [*CommonJS entry points:*](#commonjs-api) ```js core-js/proposals/array-from-async core-js(-pure)/features/array/from-async -core-js/features/typed-array/from-async ``` [*Example*](https://goo.gl/Jt7SsD): ```js @@ -2395,26 +2390,25 @@ core-js/features/typed-array/filter-reject [1, 2, 3, 4, 5].filterReject(it => it % 2); // => [2, 4] ```` ##### [`Array` grouping](#https://github.com/tc39/proposal-array-grouping)[⬆](#index) -Modules [`esnext.array.group-by`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.array.group-by.js) and [`esnext.typed-array.group-by`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.typed-array.group-by.js). +Modules [`esnext.array.group-by`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.array.group-by.js), [`esnext.array.group-by-map`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.array.group-by-map.js). ```js class Array { groupBy(callbackfn: (value: any, index: number, target: any) => key, thisArg?: any): { [key]: Array }; groupByMap(callbackfn: (value: any, index: number, target: any) => key, thisArg?: any): Map>; } - -class %TypedArray% { - groupBy(callbackfn: (value: number, index: number, target: %TypedArray%) => key, thisArg?: any): { [key]: %TypedArray% }; -} ``` [*CommonJS entry points:*](#commonjs-api) ``` core-js/proposals/array-grouping core-js(-pure)/features/array(/virtual)/group-by -core-js/features/typed-array/group-by +core-js(-pure)/features/array(/virtual)/group-by-map ``` -[*Examples*](t.ly/VggI): +[*Examples*](t.ly/xEqc): ```js [1, 2, 3, 4, 5].groupBy(it => it % 2); // => { 1: [1, 3, 5], 0: [2, 4] } +const map = [1, 2, 3, 4, 5].groupByMap(it => it % 2); +map.get(1); // => [1, 3, 5] +map.get(0); // => [2, 4] ```` ##### [Array deduplication](https://github.com/tc39/proposal-array-unique)[⬆](#index) Modules [`esnext.array.unique-by`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.array.unique-by.js) and [`esnext.typed-array.unique-by`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.typed-array.unique-by.js) @@ -3086,4 +3080,4 @@ console.log(getIteratorMethod({})); // undefined - ES `Proxy` can't be polyfilled, you can try to use [`proxy-polyfill`](https://github.com/GoogleChrome/proxy-polyfill) which provides a very little subset of features. - ES `String#normalize` is not a very useful feature, but this polyfill will be very large. If you need it, you can use [unorm](https://github.com/walling/unorm/). - ECMA-402 `Intl` is missed because of the size. You can use [those polyfills](https://formatjs.io/docs/polyfills). -- `window.fetch` is not a cross-platform feature, in some environments, it makes no sense. For this reason, I don't think it should be in `core-js`. Looking at a large number of requests it *might be* added in the future. Now you can use, for example, [this polyfill](https://github.com/github/fetch). +- `window.fetch` is not a cross-platform feature, in some environments, it makes no sense. For this reason, I don't think it should be in `core-js`. Looking at a large number of requests it *might be* added in the future. Now you can use, for example, [this polyfill](https://github.com/github/fetch). \ No newline at end of file diff --git a/packages/core-js-compat/src/data.mjs b/packages/core-js-compat/src/data.mjs index 0f56a87b9ac3..4e560dee78c1 100644 --- a/packages/core-js-compat/src/data.mjs +++ b/packages/core-js-compat/src/data.mjs @@ -1451,6 +1451,8 @@ export const data = { }, 'esnext.array.group-by': { }, + 'esnext.array.group-by-map': { + }, 'esnext.array.is-template-object': { }, // TODO: Remove from `core-js@4` @@ -1728,6 +1730,7 @@ export const data = { // TODO: Remove from `core-js@4` 'esnext.symbol.replace-all': { }, + // TODO: Remove from `core-js@4` 'esnext.typed-array.from-async': { }, // TODO: Remove from `core-js@4` @@ -1745,6 +1748,7 @@ export const data = { chrome: '97', safari: '15.4', }, + // TODO: Remove from `core-js@4` 'esnext.typed-array.group-by': { }, 'esnext.typed-array.to-reversed': { diff --git a/packages/core-js-compat/src/modules-by-versions.mjs b/packages/core-js-compat/src/modules-by-versions.mjs index 7fdc99b0080b..8d49033be63f 100644 --- a/packages/core-js-compat/src/modules-by-versions.mjs +++ b/packages/core-js-compat/src/modules-by-versions.mjs @@ -112,6 +112,7 @@ export default { 'esnext.typed-array.from-async', ], '3.20': [ + 'esnext.array.group-by-map', 'esnext.array.to-reversed', 'esnext.array.to-sorted', 'esnext.array.to-spliced', diff --git a/packages/core-js/features/array/group-by-map.js b/packages/core-js/features/array/group-by-map.js new file mode 100644 index 000000000000..0aafd2d07943 --- /dev/null +++ b/packages/core-js/features/array/group-by-map.js @@ -0,0 +1,5 @@ +require('../../modules/es.map'); +require('../../modules/esnext.array.group-by-map'); +var entryUnbind = require('../../internals/entry-unbind'); + +module.exports = entryUnbind('Array', 'groupByMap'); diff --git a/packages/core-js/features/array/index.js b/packages/core-js/features/array/index.js index 2471feaaa960..e221fa5a6126 100644 --- a/packages/core-js/features/array/index.js +++ b/packages/core-js/features/array/index.js @@ -10,6 +10,7 @@ require('../../modules/esnext.array.filter-reject'); require('../../modules/esnext.array.find-last'); require('../../modules/esnext.array.find-last-index'); require('../../modules/esnext.array.group-by'); +require('../../modules/esnext.array.group-by-map'); require('../../modules/esnext.array.is-template-object'); require('../../modules/esnext.array.last-item'); require('../../modules/esnext.array.last-index'); diff --git a/packages/core-js/features/array/virtual/group-by-map.js b/packages/core-js/features/array/virtual/group-by-map.js new file mode 100644 index 000000000000..c867311b2b79 --- /dev/null +++ b/packages/core-js/features/array/virtual/group-by-map.js @@ -0,0 +1,5 @@ +require('../../../modules/es.map'); +require('../../../modules/esnext.array.group-by-map'); +var entryVirtual = require('../../../internals/entry-virtual'); + +module.exports = entryVirtual('Array').groupByMap; diff --git a/packages/core-js/features/array/virtual/index.js b/packages/core-js/features/array/virtual/index.js index 619fda120223..eb4deb7e9bdd 100644 --- a/packages/core-js/features/array/virtual/index.js +++ b/packages/core-js/features/array/virtual/index.js @@ -8,6 +8,7 @@ require('../../../modules/esnext.array.filter-reject'); require('../../../modules/esnext.array.find-last'); require('../../../modules/esnext.array.find-last-index'); require('../../../modules/esnext.array.group-by'); +require('../../../modules/esnext.array.group-by-map'); require('../../../modules/esnext.array.to-reversed'); require('../../../modules/esnext.array.to-sorted'); require('../../../modules/esnext.array.to-spliced'); diff --git a/packages/core-js/internals/array-group-by.js b/packages/core-js/internals/array-group-by.js index f332c31f47b4..9a5310265a32 100644 --- a/packages/core-js/internals/array-group-by.js +++ b/packages/core-js/internals/array-group-by.js @@ -27,6 +27,7 @@ module.exports = function ($this, callbackfn, that, specificConstructor) { if (key in target) push(target[key], value); else target[key] = [value]; } + // TODO: Remove this block from `core-js@4` if (specificConstructor) { Constructor = specificConstructor(O); if (Constructor !== Array) { diff --git a/packages/core-js/modules/esnext.array.group-by-map.js b/packages/core-js/modules/esnext.array.group-by-map.js new file mode 100644 index 000000000000..8b1f561f87d7 --- /dev/null +++ b/packages/core-js/modules/esnext.array.group-by-map.js @@ -0,0 +1,38 @@ +'use strict'; +var $ = require('../internals/export'); +var getBuiltIn = require('../internals/get-built-in'); +var bind = require('../internals/function-bind-context'); +var uncurryThis = require('../internals/function-uncurry-this'); +var IndexedObject = require('../internals/indexed-object'); +var toObject = require('../internals/to-object'); +var lengthOfArrayLike = require('../internals/length-of-array-like'); +var addToUnscopables = require('../internals/add-to-unscopables'); + +var Map = getBuiltIn('Map'); +var MapPrototype = Map.prototype; +var mapGet = uncurryThis(MapPrototype.get); +var mapHas = uncurryThis(MapPrototype.has); +var mapSet = uncurryThis(MapPrototype.set); +var push = uncurryThis([].push); + +// `Array.prototype.groupByMap` method +// https://github.com/tc39/proposal-array-grouping +$({ target: 'Array', proto: true }, { + groupByMap: function groupByMap(callbackfn /* , thisArg */) { + var O = toObject(this); + var self = IndexedObject(O); + var boundFunction = bind(callbackfn, arguments.length > 1 ? arguments[1] : undefined); + var map = new Map(); + var length = lengthOfArrayLike(self); + var index = 0; + var key, value; + for (;length > index; index++) { + value = self[index]; + key = boundFunction(value, index, O); + if (mapHas(map, key)) push(mapGet(map, key), value); + else mapSet(map, key, [value]); + } return map; + } +}); + +addToUnscopables('groupByMap'); diff --git a/packages/core-js/modules/esnext.array.group-by.js b/packages/core-js/modules/esnext.array.group-by.js index 6e82b72f86d6..3f05a3d9d39c 100644 --- a/packages/core-js/modules/esnext.array.group-by.js +++ b/packages/core-js/modules/esnext.array.group-by.js @@ -1,7 +1,6 @@ 'use strict'; var $ = require('../internals/export'); var $groupBy = require('../internals/array-group-by'); -var arraySpeciesConstructor = require('../internals/array-species-constructor'); var addToUnscopables = require('../internals/add-to-unscopables'); // `Array.prototype.groupBy` method @@ -9,7 +8,7 @@ var addToUnscopables = require('../internals/add-to-unscopables'); $({ target: 'Array', proto: true }, { groupBy: function groupBy(callbackfn /* , thisArg */) { var thisArg = arguments.length > 1 ? arguments[1] : undefined; - return $groupBy(this, callbackfn, thisArg, arraySpeciesConstructor); + return $groupBy(this, callbackfn, thisArg); } }); diff --git a/packages/core-js/modules/esnext.typed-array.from-async.js b/packages/core-js/modules/esnext.typed-array.from-async.js index 17690e748f24..f2f5d35851b5 100644 --- a/packages/core-js/modules/esnext.typed-array.from-async.js +++ b/packages/core-js/modules/esnext.typed-array.from-async.js @@ -1,4 +1,5 @@ 'use strict'; +// TODO: Remove from `core-js@4` var getBuiltIn = require('../internals/get-built-in'); var aConstructor = require('../internals/a-constructor'); var arrayFromAsync = require('../internals/array-from-async'); diff --git a/packages/core-js/modules/esnext.typed-array.group-by.js b/packages/core-js/modules/esnext.typed-array.group-by.js index 7b42ccd8ecad..4ba0da8d074a 100644 --- a/packages/core-js/modules/esnext.typed-array.group-by.js +++ b/packages/core-js/modules/esnext.typed-array.group-by.js @@ -1,4 +1,5 @@ 'use strict'; +// TODO: Remove from `core-js@4` var ArrayBufferViewCore = require('../internals/array-buffer-view-core'); var $groupBy = require('../internals/array-group-by'); var typedArraySpeciesConstructor = require('../internals/typed-array-species-constructor'); diff --git a/packages/core-js/proposals/array-from-async.js b/packages/core-js/proposals/array-from-async.js index 6fb9c182ff16..a3ec5f4b3bbc 100644 --- a/packages/core-js/proposals/array-from-async.js +++ b/packages/core-js/proposals/array-from-async.js @@ -1,3 +1,4 @@ // https://github.com/tc39/proposal-array-from-async require('../modules/esnext.array.from-async'); +// TODO: Remove from `core-js@4` require('../modules/esnext.typed-array.from-async'); diff --git a/packages/core-js/proposals/array-grouping.js b/packages/core-js/proposals/array-grouping.js index 00a5c6fc396d..560885df2ff7 100644 --- a/packages/core-js/proposals/array-grouping.js +++ b/packages/core-js/proposals/array-grouping.js @@ -1,3 +1,5 @@ // https://github.com/tc39/proposal-array-grouping require('../modules/esnext.array.group-by'); +require('../modules/esnext.array.group-by-map'); +// TODO: Remove from `core-js@4` require('../modules/esnext.typed-array.group-by'); diff --git a/packages/core-js/stage/1.js b/packages/core-js/stage/1.js index 7d8e1e165a08..1102feae68da 100644 --- a/packages/core-js/stage/1.js +++ b/packages/core-js/stage/1.js @@ -1,6 +1,5 @@ require('../proposals/array-filtering'); require('../proposals/array-from-async'); -require('../proposals/array-grouping'); require('../proposals/array-last'); require('../proposals/array-unique'); require('../proposals/collection-methods'); diff --git a/packages/core-js/stage/2.js b/packages/core-js/stage/2.js index 838b1168bcae..30c0e66b9d82 100644 --- a/packages/core-js/stage/2.js +++ b/packages/core-js/stage/2.js @@ -1,3 +1,4 @@ +require('../proposals/array-grouping'); require('../proposals/array-is-template-object'); require('../proposals/change-array-by-copy'); require('../proposals/decorators'); diff --git a/scripts/check-compat-tests.mjs b/scripts/check-compat-tests.mjs index c7c71bfd8d22..1f8484e82bf2 100644 --- a/scripts/check-compat-tests.mjs +++ b/scripts/check-compat-tests.mjs @@ -30,7 +30,9 @@ const ignore = new Set([ 'esnext.string.at', 'esnext.symbol.pattern-match', 'esnext.symbol.replace-all', + 'esnext.typed-array.from-async', 'esnext.typed-array.filter-out', + 'esnext.typed-array.group-by', 'esnext.weak-map.upsert', ]); diff --git a/tests/commonjs.mjs b/tests/commonjs.mjs index d5d893f5906b..0f27ba9e8b7c 100644 --- a/tests/commonjs.mjs +++ b/tests/commonjs.mjs @@ -567,6 +567,7 @@ for (PATH of ['core-js-pure', 'core-js']) { ok(load(NS, 'array/find-last')([1, 2, 3], it => it % 2) === 3); ok(load(NS, 'array/find-last-index')([1, 2, 3], it => it % 2) === 2); ok(typeof load(NS, 'array/group-by') == 'function'); + ok(typeof load(NS, 'array/group-by-map') == 'function'); ok(typeof load(NS, 'array/is-template-object') == 'function'); load(NS, 'array/last-item'); load(NS, 'array/last-index'); @@ -580,6 +581,7 @@ for (PATH of ['core-js-pure', 'core-js']) { ok(load(NS, 'array/virtual/find-last').call([1, 2, 3], it => it % 2) === 3); ok(load(NS, 'array/virtual/find-last-index').call([1, 2, 3], it => it % 2) === 2); ok(typeof load(NS, 'array/virtual/group-by') == 'function'); + ok(typeof load(NS, 'array/virtual/group-by-map') == 'function'); ok(typeof load(NS, 'array/virtual/unique-by') == 'function'); ok(load(NS, 'array/virtual/with').call([1, 2, 3], 1, 4)); ok(load(NS, 'array/virtual/to-reversed').call([1, 2, 3])[0] === 3); diff --git a/tests/compat/tests.js b/tests/compat/tests.js index 4f2191564ae8..2397ce30b617 100644 --- a/tests/compat/tests.js +++ b/tests/compat/tests.js @@ -1514,9 +1514,6 @@ GLOBAL.tests = { 'esnext.symbol.observable': function () { return Symbol.observable; }, - 'esnext.typed-array.from-async': function () { - return Int8Array.fromAsync; - }, 'esnext.typed-array.filter-reject': function () { return Int8Array.prototype.filterReject; }, @@ -1526,9 +1523,6 @@ GLOBAL.tests = { 'esnext.typed-array.find-last-index': function () { return Int8Array.prototype.findLastIndex; }, - 'esnext.typed-array.group-by': function () { - return Int8Array.prototype.groupBy; - }, 'esnext.typed-array.to-reversed': function () { return Int8Array.prototype.toReversed; }, diff --git a/tests/pure/esnext.array.group-by-map.js b/tests/pure/esnext.array.group-by-map.js new file mode 100644 index 000000000000..e28b3d3717e9 --- /dev/null +++ b/tests/pure/esnext.array.group-by-map.js @@ -0,0 +1,37 @@ +import { STRICT } from '../helpers/constants'; + +import Map from 'core-js-pure/es/map'; +import Symbol from 'core-js-pure/es/symbol'; +import from from 'core-js-pure/es/array/from'; +import groupByMap from 'core-js-pure/features/array/group-by-map'; + +QUnit.test('Array#groupByMap', assert => { + assert.isFunction(groupByMap); + let array = [1]; + const context = {}; + groupByMap(array, function (value, key, that) { + assert.same(arguments.length, 3, 'correct number of callback arguments'); + assert.same(value, 1, 'correct value in callback'); + assert.same(key, 0, 'correct index in callback'); + assert.same(that, array, 'correct link to array in callback'); + assert.same(this, context, 'correct callback context'); + }, context); + assert.true(groupByMap([], it => it) instanceof Map, 'returns Map'); + assert.deepEqual(from(groupByMap([1, 2, 3], it => it % 2)), [[1, [1, 3]], [0, [2]]], '#1'); + assert.deepEqual( + from(groupByMap([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], it => `i${ it % 5 }`)), + [['i1', [1, 6, 11]], ['i2', [2, 7, 12]], ['i3', [3, 8]], ['i4', [4, 9]], ['i0', [5, 10]]], + '#2', + ); + assert.deepEqual(from(groupByMap(Array(3), it => it)), [[undefined, [undefined, undefined, undefined]]], '#3'); + if (STRICT) { + assert.throws(() => groupByMap(null, () => { /* empty */ }), TypeError); + assert.throws(() => groupByMap(undefined, () => { /* empty */ }), TypeError); + } + array = [1]; + // eslint-disable-next-line object-shorthand -- constructor + array.constructor = { [Symbol.species]: function () { + return { foo: 1 }; + } }; + assert.same(groupByMap(array, Boolean).get(true).foo, undefined, 'no @@species'); +}); diff --git a/tests/pure/esnext.array.group-by.js b/tests/pure/esnext.array.group-by.js index 252e8490b7dd..2b9492d62076 100644 --- a/tests/pure/esnext.array.group-by.js +++ b/tests/pure/esnext.array.group-by.js @@ -32,5 +32,5 @@ QUnit.test('Array#groupBy', assert => { array.constructor = { [Symbol.species]: function () { return { foo: 1 }; } }; - assert.same(groupBy(array, Boolean).true.foo, 1, '@@species'); + assert.same(groupBy(array, Boolean).true.foo, undefined, 'no @@species'); }); diff --git a/tests/tests/esnext.array.group-by-map.js b/tests/tests/esnext.array.group-by-map.js new file mode 100644 index 000000000000..34547c458505 --- /dev/null +++ b/tests/tests/esnext.array.group-by-map.js @@ -0,0 +1,39 @@ +import { STRICT } from '../helpers/constants'; + +const { from } = Array; + +QUnit.test('Array#groupByMap', assert => { + const { groupByMap } = Array.prototype; + assert.isFunction(groupByMap); + assert.arity(groupByMap, 1); + assert.name(groupByMap, 'groupByMap'); + assert.looksNative(groupByMap); + assert.nonEnumerable(Array.prototype, 'groupByMap'); + let array = [1]; + const context = {}; + array.groupByMap(function (value, key, that) { + assert.same(arguments.length, 3, 'correct number of callback arguments'); + assert.same(value, 1, 'correct value in callback'); + assert.same(key, 0, 'correct index in callback'); + assert.same(that, array, 'correct link to array in callback'); + assert.same(this, context, 'correct callback context'); + }, context); + assert.true([].groupByMap(it => it) instanceof Map, 'returns Map'); + assert.deepEqual(from([1, 2, 3].groupByMap(it => it % 2)), [[1, [1, 3]], [0, [2]]], '#1'); + assert.deepEqual( + from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12].groupByMap(it => `i${ it % 5 }`)), + [['i1', [1, 6, 11]], ['i2', [2, 7, 12]], ['i3', [3, 8]], ['i4', [4, 9]], ['i0', [5, 10]]], + '#2', + ); + assert.deepEqual(from(Array(3).groupByMap(it => it)), [[undefined, [undefined, undefined, undefined]]], '#3'); + if (STRICT) { + assert.throws(() => groupByMap.call(null, () => { /* empty */ }), TypeError); + assert.throws(() => groupByMap.call(undefined, () => { /* empty */ }), TypeError); + } + array = [1]; + // eslint-disable-next-line object-shorthand -- constructor + array.constructor = { [Symbol.species]: function () { + return { foo: 1 }; + } }; + assert.same(array.groupByMap(Boolean).get(true).foo, undefined, 'no @@species'); +}); diff --git a/tests/tests/esnext.array.group-by.js b/tests/tests/esnext.array.group-by.js index c3fe51c91e35..6801b44c8d18 100644 --- a/tests/tests/esnext.array.group-by.js +++ b/tests/tests/esnext.array.group-by.js @@ -35,5 +35,5 @@ QUnit.test('Array#groupBy', assert => { array.constructor = { [Symbol.species]: function () { return { foo: 1 }; } }; - assert.same(array.groupBy(Boolean).true.foo, 1, '@@species'); + assert.same(array.groupBy(Boolean).true.foo, undefined, 'no @@species'); });