diff --git a/CHANGELOG.md b/CHANGELOG.md index eb7f2c673fa6..af6e1212939e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ - `Array#findLastIndex` - `%TypedArray%#findLast` - `%TypedArray%#findLastIndex` +- Added `%TypedArray%#uniqueBy` method for [array deduplication stage 1 proposal](https://github.com/tc39/proposal-array-unique) + - `%TypedArray%#uniqueBy` - Dropped `ToLength` detection from array methods feature detection which could cause hanging FF11-21 and some versions of old WebKit, [#764](https://github.com/zloirock/core-js/issues/764) - Minified bundle from `core-js-bundle` uses `terser` instead of `uglify-js` diff --git a/README.md b/README.md index 29e89bd035a3..c7dacc2ced30 100644 --- a/README.md +++ b/README.md @@ -1468,10 +1468,13 @@ class [ Uint32Array, Float32Array, Float64Array, -] { +] extends %TypedArray% { constructor(length: number): %TypedArray%; constructor(object: %TypedArray% | Iterable | ArrayLike): %TypedArray%; - constructor(buffer: ArrayBuffer, byteOffset?: number, length?: number): %TypedArray%; + constructor(buffer: ArrayBuffer, byteOffset?: number, length?: number): %TypedArray% +} + +class %TypedArray% { copyWithin(target: number, start: number, end?: number): this; every(callbackfn: (value: number, index: number, target: %TypedArray%) => boolean, thisArg?: any): boolean; fill(value: number, start?: number, end?: number): this; @@ -1787,17 +1790,7 @@ class Array { at(index: int): any; } -class [ - Int8Array, - Uint8Array, - Uint8ClampedArray, - Int16Array, - Uint16Array, - Int32Array, - Uint32Array, - Float32Array, - Float64Array, -] { +class %TypedArray% { at(index: int): any; } ``` @@ -2402,17 +2395,7 @@ class Array { filterOut(callbackfn: (value: any, index: number, target: any) => boolean, thisArg?: any): Array; } -class [ - Int8Array, - Uint8Array, - Uint8ClampedArray, - Int16Array, - Uint16Array, - Int32Array, - Uint32Array, - Float32Array, - Float64Array, -] { +class %TypedArray% { filterOut(callbackfn: (value: number, index: number, target: %TypedArray%) => boolean, thisArg?: any): %TypedArray%; } ``` @@ -2420,23 +2403,28 @@ class [ ``` core-js/proposals/array-filtering core-js(-pure)/features/array(/virtual)/filter-out -core-js(-pure)/features/typed-array/filter-out +core-js/features/typed-array/filter-out ``` [*Examples*](http://es6.zloirock.ru/#log(%5B1%2C%202%2C%203%2C%204%2C%205%5D.filterOut(it%20%3D%3E%20it%20%25%202))%3B%20%2F%2F%20%3D%3E%20%5B2%2C%204%5D): ```js [1, 2, 3, 4, 5].filterOut(it => it % 2); // => [2, 4] ```` ##### [Array deduplication](https://github.com/tc39/proposal-array-unique)[⬆](#index) -Module [`esnext.array.unique-by`](https://github.com/zloirock/core-js/blob/v3.8.3/packages/core-js/modules/esnext.array.unique-by.js) +Modules [`esnext.array.unique-by`](https://github.com/zloirock/core-js/blob/v3.8.3/packages/core-js/modules/esnext.array.unique-by.js) and [`esnext.typed-array.unique-by`](https://github.com/zloirock/core-js/blob/v3.8.3/packages/core-js/modules/esnext.typed-array.unique-by.js) ```js class Array { uniqueBy(resolver?: (item: any) => any): Array; } + +class %TypedArray% { + uniqueBy(resolver?: (item: any) => any): %TypedArray%;; +} ``` [*CommonJS entry points:*](#commonjs-api) ``` core-js/proposals/array-unique core-js(-pure)/features/array(/virtual)/unique-by +core-js/features/typed-array/unique-by ``` [*Examples*](http://es6.zloirock.ru/#log(%5B1%2C%202%2C%203%2C%202%2C%201%5D.uniqueBy())%3B%20%20%2F%2F%20%5B1%2C%202%2C%203%5D%0A%0Aconst%20data%20%3D%20%5B%0A%20%20%7B%20id%3A%201%2C%20uid%3A%2010000%20%7D%2C%0A%20%20%7B%20id%3A%202%2C%20uid%3A%2010000%20%7D%2C%0A%20%20%7B%20id%3A%203%2C%20uid%3A%2010001%20%7D%0A%5D%3B%0A%0Alog(data.uniqueBy('uid'))%3B%20%2F%2F%20%3D%3E%20%5B%7B%20id%3A%201%2C%20uid%3A%2010000%20%7D%2C%20%7B%20id%3A%203%2C%20uid%3A%2010001%20%7D%5D%0A%0Alog(data.uniqueBy((%7B%20id%2C%20uid%20%7D)%20%3D%3E%20%60%24%7Bid%7D-%24%7Buid%7D%60))%3B%20%2F%2F%20%3D%3E%20%5B%7B%20id%3A%201%2C%20uid%3A%2010000%20%7D%2C%20%7B%20id%3A%202%2C%20uid%3A%2010000%20%7D%2C%20%7B%20id%3A%203%2C%20uid%3A%2010001%20%7D%5D): ```js @@ -2456,17 +2444,7 @@ class Array { findLastIndex(callbackfn: (value: any, index: number, target: any) => boolean, thisArg?: any): uint; } -class [ - Int8Array, - Uint8Array, - Uint8ClampedArray, - Int16Array, - Uint16Array, - Int32Array, - Uint32Array, - Float32Array, - Float64Array, -] { +class %TypedArray% { findLast(callbackfn: (value: any, index: number, target: %TypedArray%) => boolean, thisArg?: any): any; findLastIndex(callbackfn: (value: any, index: number, target: %TypedArray%) => boolean, thisArg?: any): uint; } @@ -2476,8 +2454,8 @@ class [ core-js/proposals/array-find-from-last core-js(-pure)/features(/virtual)/array/find-last core-js(-pure)/features(/virtual)/array/find-last-index -core-js(-pure)/features/typed-array/find-last -core-js(-pure)/features/typed-array/find-last-index +core-js/features/typed-array/find-last +core-js/features/typed-array/find-last-index ``` [*Examples*](http://es6.zloirock.ru/#log(%5B1%2C%202%2C%203%2C%204%5D.findLast(it%20%3D%3E%20it%20%25%202))%3B%20%20%20%20%20%20%2F%2F%20%3D%3E%203%0Alog(%5B1%2C%202%2C%203%2C%204%5D.findLastIndex(it%20%3D%3E%20it%20%25%202))%3B%20%2F%2F%20%3D%3E%202): ```js diff --git a/packages/core-js-compat/src/data.js b/packages/core-js-compat/src/data.js index 90f0d2ea2f2b..5aede774b776 100644 --- a/packages/core-js-compat/src/data.js +++ b/packages/core-js-compat/src/data.js @@ -1506,6 +1506,8 @@ const data = { }, 'esnext.typed-array.find-last-index': { }, + 'esnext.typed-array.unique-by': { + }, 'esnext.weak-map.delete-all': { }, 'esnext.weak-map.from': { diff --git a/packages/core-js-compat/src/modules-by-versions.js b/packages/core-js-compat/src/modules-by-versions.js index 3f52e1c95e50..9f77400ca58e 100644 --- a/packages/core-js-compat/src/modules-by-versions.js +++ b/packages/core-js-compat/src/modules-by-versions.js @@ -78,5 +78,6 @@ module.exports = { 'esnext.array.find-last-index', 'esnext.typed-array.find-last', 'esnext.typed-array.find-last-index', + 'esnext.typed-array.unique-by', ], }; diff --git a/packages/core-js-pure/override/modules/esnext.typed-array.unique-by.js b/packages/core-js-pure/override/modules/esnext.typed-array.unique-by.js new file mode 100644 index 000000000000..8b1a393741c9 --- /dev/null +++ b/packages/core-js-pure/override/modules/esnext.typed-array.unique-by.js @@ -0,0 +1 @@ +// empty diff --git a/packages/core-js/features/array/virtual/index.js b/packages/core-js/features/array/virtual/index.js index f10b61a66662..61ea0b19c809 100644 --- a/packages/core-js/features/array/virtual/index.js +++ b/packages/core-js/features/array/virtual/index.js @@ -1,4 +1,5 @@ var parent = require('../../../es/array/virtual'); +require('../../../modules/es.map'); require('../../../modules/esnext.array.at'); require('../../../modules/esnext.array.filter-out'); require('../../../modules/esnext.array.find-last'); diff --git a/packages/core-js/features/typed-array/index.js b/packages/core-js/features/typed-array/index.js index 65c33e2b7876..1a10f95266bc 100644 --- a/packages/core-js/features/typed-array/index.js +++ b/packages/core-js/features/typed-array/index.js @@ -1,7 +1,9 @@ var parent = require('../../es/typed-array'); +require('../../modules/es.map'); require('../../modules/esnext.typed-array.at'); require('../../modules/esnext.typed-array.filter-out'); require('../../modules/esnext.typed-array.find-last'); require('../../modules/esnext.typed-array.find-last-index'); +require('../../modules/esnext.typed-array.unique-by'); module.exports = parent; diff --git a/packages/core-js/features/typed-array/unique-by.js b/packages/core-js/features/typed-array/unique-by.js new file mode 100644 index 000000000000..c4ddd3512370 --- /dev/null +++ b/packages/core-js/features/typed-array/unique-by.js @@ -0,0 +1,2 @@ +require('../../modules/es.map'); +require('../../modules/esnext.typed-array.unique-by'); diff --git a/packages/core-js/internals/array-unique-by.js b/packages/core-js/internals/array-unique-by.js new file mode 100644 index 000000000000..d470d4013750 --- /dev/null +++ b/packages/core-js/internals/array-unique-by.js @@ -0,0 +1,32 @@ +'use strict'; +var toLength = require('../internals/to-length'); +var toObject = require('../internals/to-object'); +var getBuiltIn = require('../internals/get-built-in'); +var arraySpeciesCreate = require('../internals/array-species-create'); + +var push = [].push; + +// `Array.prototype.uniqueBy` method +// https://github.com/tc39/proposal-array-unique +module.exports = function uniqueBy(resolver) { + var that = toObject(this); + var length = toLength(that.length); + var result = arraySpeciesCreate(that, 0); + var Map = getBuiltIn('Map'); + var map = new Map(); + var resolverFunction, index, item, key; + if (typeof resolver == 'function') resolverFunction = resolver; + else if (resolver == null) resolverFunction = function (value) { + return value; + }; + else throw new TypeError('Incorrect resolver!'); + for (index = 0; index < length; index++) { + item = that[index]; + key = resolverFunction(item); + if (!map.has(key)) map.set(key, item); + } + map.forEach(function (value) { + push.call(result, value); + }); + return result; +}; diff --git a/packages/core-js/internals/typed-array-from-species-and-list.js b/packages/core-js/internals/typed-array-from-species-and-list.js new file mode 100644 index 000000000000..b4998ae53a23 --- /dev/null +++ b/packages/core-js/internals/typed-array-from-species-and-list.js @@ -0,0 +1,11 @@ +var aTypedArrayConstructor = require('../internals/array-buffer-view-core').aTypedArrayConstructor; +var speciesConstructor = require('../internals/species-constructor'); + +module.exports = function (instance, list) { + var C = speciesConstructor(instance, instance.constructor); + var index = 0; + var length = list.length; + var result = new (aTypedArrayConstructor(C))(length); + while (length > index) result[index] = list[index++]; + return result; +}; diff --git a/packages/core-js/modules/es.typed-array.filter.js b/packages/core-js/modules/es.typed-array.filter.js index 7787c5e594b3..9d22eef3749a 100644 --- a/packages/core-js/modules/es.typed-array.filter.js +++ b/packages/core-js/modules/es.typed-array.filter.js @@ -1,20 +1,14 @@ 'use strict'; var ArrayBufferViewCore = require('../internals/array-buffer-view-core'); var $filter = require('../internals/array-iteration').filter; -var speciesConstructor = require('../internals/species-constructor'); +var fromSpeciesAndList = require('../internals/typed-array-from-species-and-list'); var aTypedArray = ArrayBufferViewCore.aTypedArray; -var aTypedArrayConstructor = ArrayBufferViewCore.aTypedArrayConstructor; var exportTypedArrayMethod = ArrayBufferViewCore.exportTypedArrayMethod; // `%TypedArray%.prototype.filter` method // https://tc39.es/ecma262/#sec-%typedarray%.prototype.filter exportTypedArrayMethod('filter', function filter(callbackfn /* , thisArg */) { var list = $filter(aTypedArray(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined); - var C = speciesConstructor(this, this.constructor); - var index = 0; - var length = list.length; - var result = new (aTypedArrayConstructor(C))(length); - while (length > index) result[index] = list[index++]; - return result; + return fromSpeciesAndList(this, list); }); diff --git a/packages/core-js/modules/esnext.array.unique-by.js b/packages/core-js/modules/esnext.array.unique-by.js index c7d1bf6e6f28..6f23dcff04eb 100644 --- a/packages/core-js/modules/esnext.array.unique-by.js +++ b/packages/core-js/modules/esnext.array.unique-by.js @@ -1,38 +1,12 @@ 'use strict'; var $ = require('../internals/export'); -var toLength = require('../internals/to-length'); -var toObject = require('../internals/to-object'); -var getBuiltIn = require('../internals/get-built-in'); -var arraySpeciesCreate = require('../internals/array-species-create'); var addToUnscopables = require('../internals/add-to-unscopables'); - -var push = [].push; +var uniqueBy = require('../internals/array-unique-by'); // `Array.prototype.uniqueBy` method // https://github.com/tc39/proposal-array-unique $({ target: 'Array', proto: true }, { - uniqueBy: function uniqueBy(resolver) { - var that = toObject(this); - var length = toLength(that.length); - var result = arraySpeciesCreate(that, 0); - var Map = getBuiltIn('Map'); - var map = new Map(); - var resolverFunction, index, item, key; - if (typeof resolver == 'function') resolverFunction = resolver; - else if (resolver == null) resolverFunction = function (value) { - return value; - }; - else throw new TypeError('Incorrect resolver!'); - for (index = 0; index < length; index++) { - item = that[index]; - key = resolverFunction(item); - if (!map.has(key)) map.set(key, item); - } - map.forEach(function (value) { - push.call(result, value); - }); - return result; - } + uniqueBy: uniqueBy }); addToUnscopables('uniqueBy'); diff --git a/packages/core-js/modules/esnext.typed-array.filter-out.js b/packages/core-js/modules/esnext.typed-array.filter-out.js index d283790b406b..c252ec6b7db9 100644 --- a/packages/core-js/modules/esnext.typed-array.filter-out.js +++ b/packages/core-js/modules/esnext.typed-array.filter-out.js @@ -1,20 +1,14 @@ 'use strict'; var ArrayBufferViewCore = require('../internals/array-buffer-view-core'); var $filterOut = require('../internals/array-iteration').filterOut; -var speciesConstructor = require('../internals/species-constructor'); +var fromSpeciesAndList = require('../internals/typed-array-from-species-and-list'); var aTypedArray = ArrayBufferViewCore.aTypedArray; -var aTypedArrayConstructor = ArrayBufferViewCore.aTypedArrayConstructor; var exportTypedArrayMethod = ArrayBufferViewCore.exportTypedArrayMethod; // `%TypedArray%.prototype.filterOut` method // https://github.com/tc39/proposal-array-filtering exportTypedArrayMethod('filterOut', function filterOut(callbackfn /* , thisArg */) { var list = $filterOut(aTypedArray(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined); - var C = speciesConstructor(this, this.constructor); - var index = 0; - var length = list.length; - var result = new (aTypedArrayConstructor(C))(length); - while (length > index) result[index] = list[index++]; - return result; + return fromSpeciesAndList(this, list); }); diff --git a/packages/core-js/modules/esnext.typed-array.unique-by.js b/packages/core-js/modules/esnext.typed-array.unique-by.js new file mode 100644 index 000000000000..659395a79982 --- /dev/null +++ b/packages/core-js/modules/esnext.typed-array.unique-by.js @@ -0,0 +1,13 @@ +'use strict'; +var ArrayBufferViewCore = require('../internals/array-buffer-view-core'); +var arrayUniqueBy = require('../internals/array-unique-by'); +var fromSpeciesAndList = require('../internals/typed-array-from-species-and-list'); + +var aTypedArray = ArrayBufferViewCore.aTypedArray; +var exportTypedArrayMethod = ArrayBufferViewCore.exportTypedArrayMethod; + +// `%TypedArray%.prototype.uniqueBy` method +// https://github.com/tc39/proposal-array-unique +exportTypedArrayMethod('uniqueBy', function uniqueBy(resolver) { + return fromSpeciesAndList(this, arrayUniqueBy.call(aTypedArray(this), resolver)); +}); diff --git a/packages/core-js/proposals/array-unique.js b/packages/core-js/proposals/array-unique.js index 855fe24a36b3..b8a74da896a2 100644 --- a/packages/core-js/proposals/array-unique.js +++ b/packages/core-js/proposals/array-unique.js @@ -1,3 +1,4 @@ // https://github.com/tc39/proposal-array-unique require('../modules/es.map'); require('../modules/esnext.array.unique-by'); +require('../modules/esnext.typed-array.unique-by'); diff --git a/tests/commonjs.js b/tests/commonjs.js index fcb86bc4da72..c943d37a8ca0 100644 --- a/tests/commonjs.js +++ b/tests/commonjs.js @@ -1707,6 +1707,7 @@ load('features/typed-array/sort'); load('features/typed-array/subarray'); load('features/typed-array/to-locale-string'); load('features/typed-array/to-string'); +load('features/typed-array/unique-by'); load('features/typed-array/values'); ok(typeof load('features/typed-array').Uint32Array === 'function'); ok(typeof load('es/string/match') === 'function'); diff --git a/tests/tests/esnext.typed-array.unique-by.js b/tests/tests/esnext.typed-array.unique-by.js new file mode 100644 index 000000000000..fcb4052408fb --- /dev/null +++ b/tests/tests/esnext.typed-array.unique-by.js @@ -0,0 +1,24 @@ +import { DESCRIPTORS, GLOBAL, TYPED_ARRAYS } from '../helpers/constants'; + +if (DESCRIPTORS) QUnit.test('%TypedArrayPrototype%.uniqueBy', assert => { + // we can't implement %TypedArrayPrototype% in all engines, so run all tests for each typed array constructor + for (const name in TYPED_ARRAYS) { + const TypedArray = GLOBAL[name]; + const { uniqueBy } = TypedArray.prototype; + assert.isFunction(uniqueBy, `${ name }::uniqueBy is function`); + assert.arity(uniqueBy, 1, `${ name }::uniqueBy arity is 1`); + assert.name(uniqueBy, 'uniqueBy', `${ name }::uniqueBy name is 'uniqueBy'`); + assert.looksNative(uniqueBy, `${ name }::uniqueBy looks native`); + const array = new TypedArray([1, 2, 3, 2, 1]); + assert.ok(array.uniqueBy() !== array); + assert.deepEqual(array.uniqueBy(), new TypedArray([1, 2, 3])); + let values = ''; + new TypedArray([1, 2, 3]).uniqueBy(value => { + values += value; + }); + assert.same(values, '123'); + assert.throws(() => uniqueBy.call(null, () => { /* empty */ }), TypeError); + assert.throws(() => uniqueBy.call(undefined, () => { /* empty */ }), TypeError); + assert.throws(() => uniqueBy.call([0], () => { /* empty */ }), "isn't generic"); + } +}); diff --git a/tests/tests/index.js b/tests/tests/index.js index 150a24f8563d..bbfb3a0b69c8 100644 --- a/tests/tests/index.js +++ b/tests/tests/index.js @@ -316,6 +316,7 @@ import './esnext.typed-array.at'; import './esnext.typed-array.filter-out'; import './esnext.typed-array.find-last'; import './esnext.typed-array.find-last-index'; +import './esnext.typed-array.unique-by'; import './esnext.weak-map.delete-all'; import './esnext.weak-map.from'; import './esnext.weak-map.of';