Bind: Add Array.includes to bind#7401
Conversation
|
/to @choumx @jridgewell |
jridgewell
left a comment
There was a problem hiding this comment.
Need tests, explicitly:
NaNshould findNaN-0and0should find either.undefinedshould findundefined, notnullnullshould findnull, notundefined- Any number should find itself
- Any string should find itself
- Any boolean should find itself
- Any object should find explicitly itself
src/polyfills/array.js
Outdated
| export function install(win) { | ||
| if (!win.Array.prototype.includes) { | ||
| /*eslint "no-extend-native": 0*/ | ||
| Object.defineProperty(Array.prototype, 'includes', {value: includes}); |
src/polyfills/array.js
Outdated
| throw new TypeError('"this" is null or not defined'); | ||
| } | ||
| const o = Object(this); | ||
| const len = o.length >>> 0; |
There was a problem hiding this comment.
Replaced with your version
src/polyfills/array.js
Outdated
| const n = fromIndex | 0; | ||
| let k = Math.max(n >= 0 ? n : len - Math.abs(n), 0); | ||
| while (k < len) { | ||
| if (o[k] === searchElement) { |
There was a problem hiding this comment.
This will fail [NaN].includes(NaN)
There was a problem hiding this comment.
Replaced with your version
src/polyfills/array.js
Outdated
| * @param {number} fromIndex | ||
| * @returns {boolean} | ||
| */ | ||
| export function includes(searchElement, fromIndex) { |
There was a problem hiding this comment.
So, we can optimize a bit:
function includes(value, fromIndex) {
if (value === value) { // Everything but NaN
return this.indexOf(value, fromIndex) > -1;
}
let i = Math.max(n >= 0 ? n : len + n, 0);
for (; i < this.length; i++) {
const value = this[i];
if (value !== value) {
return true;
}
}
return false;
}|
Added tests |
src/polyfills/array.js
Outdated
| * @param {!Window} win | ||
| */ | ||
| export function install(win) { | ||
| if (!win.Array.includes) { |
There was a problem hiding this comment.
Array.prototype.includes. What's there now is a static method on Array.
src/polyfills.js
Outdated
| import {install as installMathSign} from './polyfills/math-sign'; | ||
| import {install as installObjectAssign} from './polyfills/object-assign'; | ||
| import {install as installPromise} from './polyfills/promise'; | ||
| import {install as installArray} from './polyfills/array'; |
There was a problem hiding this comment.
Let's rename the file to array-includes to match the other method polyfills.
src/polyfills/array.js
Outdated
| */ | ||
| export function includes(value, fromIndex) { | ||
| /* eslint no-self-compare: 0 */ | ||
| if (value === value) { // Everything but NaN |
There was a problem hiding this comment.
Thinking about this more, let's drop this and push all cases into the for loop. We'll need to change it a bit:
const other = this[i];
if (other === value || (value !== value && other !== other)) {
return true;
}
src/polyfills/array.js
Outdated
| /** | ||
| * Returns true if the element is in the array and false otherwise. | ||
| * | ||
| * @param {*} searchElement |
|
|
||
|
|
||
| /** | ||
| * Returns true if the element is in the array and false otherwise. |
There was a problem hiding this comment.
Perhaps add an @see annotation with the MDN link.
There was a problem hiding this comment.
Since we're not using that version anymore, I don't think that'll be necessary.
|
|
||
| describe('Array.includes', () => { | ||
|
|
||
| const arrayWithPrimitives = [false, 17, 'hello world']; |
There was a problem hiding this comment.
Move this into the it() method. Ditto for other tests below.
src/polyfills/array.js
Outdated
| * @param {number} fromIndex | ||
| * @returns {boolean} | ||
| */ | ||
| export function includes(value, fromIndex) { |
There was a problem hiding this comment.
Does this need to be exported? If not, you can use a mock Window object with install() below to access it for testing.
src/polyfills/array.js
Outdated
| } | ||
| fromIndex = fromIndex || 0; | ||
| const len = this.length; | ||
| let i = Math.max(fromIndex >= 0 ? fromIndex : len + fromIndex, 0); |
There was a problem hiding this comment.
You only need to max the false branch of the ternary, right? I think that would be a bit more readable too.
| fromIndex = fromIndex || 0; | ||
| const len = this.length; | ||
| let i = Math.max(fromIndex >= 0 ? fromIndex : len + fromIndex, 0); | ||
| for (; i < len; i++) { |
There was a problem hiding this comment.
Any reason why you're declaring i outside the loop?
There was a problem hiding this comment.
Don't want the line to be too long
src/polyfills/array-includes.js
Outdated
| * @returns {boolean} | ||
| */ | ||
| function includes(value, fromIndex) { | ||
| /* eslint no-self-compare: 0 */ |
src/polyfills/array-includes.js
Outdated
| * Returns true if the element is in the array and false otherwise. | ||
| * | ||
| * @param {*} value | ||
| * @param {number} fromIndex |
There was a problem hiding this comment.
For optional params:
@param {number=} opt_fromIndex
src/polyfills/array-includes.js
Outdated
| */ | ||
| function includes(value, fromIndex) { | ||
| /* eslint no-self-compare: 0 */ | ||
| fromIndex = fromIndex || 0; |
There was a problem hiding this comment.
@jridgewell Do we support default parameters yet? Looks like Babel/Closure has basic support.
| let i = fromIndex >= 0 ? fromIndex : Math.max(len + fromIndex, 0); | ||
| for (; i < len; i++) { | ||
| const other = this[i]; | ||
| if (other === value || (value !== value && other !== other)) { |
There was a problem hiding this comment.
Can you add a comment explaining value !== value?
jridgewell
left a comment
There was a problem hiding this comment.
I think a nice next step is to find anywhere that does Arary#indexOf > -1 (or one of the == -1, >= 0, < 0) and update them to #includes. You'll also need to remove our Array#includes ban.
src/polyfills.js
Outdated
| import {install as installMathSign} from './polyfills/math-sign'; | ||
| import {install as installObjectAssign} from './polyfills/object-assign'; | ||
| import {install as installPromise} from './polyfills/promise'; | ||
| import {install as installArray} from './polyfills/array-includes'; |
There was a problem hiding this comment.
Nit: rename to installArrayIncludes
|
Can do, but would prefer not to clutter this PR. |
Yah, I meant as a follow up. |
|
Looks good. Last thing: can you check the impact to file size for v0.js? |
src/polyfills/array-includes.js
Outdated
| * | ||
| * @param {*} value | ||
| * @param {number=} opt_fromIndex | ||
| * @returns {boolean} |
|
+222 bytes |
|
Fixes #7378 |
* add array polyfill, whitelist contains function * install the polyfill * debuggign test * typos * cleanup * cleanup * contains -> includes * more cleanup * forgot to update one contains to includes * whitelist * fix failing test * pr comments * added test * fixed slight issue with the polyfill * add test * typo * pr comments * cleanup * cleanup * pr comments * ci issues * more ci issues * even more ci issues * update whitelist * pr comments * remove ban on includes * pr comments
* add array polyfill, whitelist contains function * install the polyfill * debuggign test * typos * cleanup * cleanup * contains -> includes * more cleanup * forgot to update one contains to includes * whitelist * fix failing test * pr comments * added test * fixed slight issue with the polyfill * add test * typo * pr comments * cleanup * cleanup * pr comments * ci issues * more ci issues * even more ci issues * update whitelist * pr comments * remove ban on includes * pr comments
Adds "Array.includes" to bind. Also adds a polyfill for Array.includes.