Accepting an array as the first parameter to String.prototype.includes
Edwin Reynoso wrote:
There are times where I would like to check whether a string has every occurrence of certain strings/numbers:
Now to achieve what I would like
String.prototype.includes
to
accomplish
with an array as the first parameter, I currently take the following approach:
var str = "John,Mary,Bob,Steve"; var names = ["Mary", "Bob"]; names.every(name => str.includes(name)); // true;
And that's perfectly fine imho, pretty expressive about what is done
about the array. Just passing an array to .includes
is rather
meaningless (not denotative).
If we need a method to do this (to allow for native optimisations with
fancy string search algorithms), I'd suggest to use a different method
name like String.prototype.includesAll
.
Bergi
I'm still having hard time understanding what's the difference between contains and the good old indexOf beside the RegExp check ... but I agree having multiple explicit searches instead of multiple implicit searches won't make such big difference. Good news is, you probably will still use RegExp anyway because names can be composed and haveing a \bName\b helper is probably what you might need anyway :-)
i.e. Maria !== Marianne
On 3/10/15, Andrea Giammarchi <andrea.giammarchi at gmail.com> wrote:
I'm still having hard time understanding what's the difference between contains and the good old indexOf beside the RegExp check ... but I agree having multiple explicit searches instead of multiple implicit searches won't make such big difference. Good news is, you probably will still use RegExp anyway because names can be composed and haveing a \bName\b helper is probably what you might need anyway :-)
i.e. Maria !== Marianne
What if Array had a contains or containsAll functions?
var s = "Maria, Mariana"; var a = s.split(/\s*,\s*/); ["Maria", "Mariana"].every(e=>{return a.indexOf(e)!=-1}); true
But a contains
function might be better than indexOf
["Maria", "Mariana"].every(e=>{return a.contains(e)});
But containsAll
might be even better.
a.containsAll(["Maria", "Mariana"]) seems even easier to read for me.
There is already filter
for exclusions. What about merging arrays?
Array.union(array2, array3, ...);
Would new Set(arr.concat(substrings)).length === arr.length
work?
Personally I find the "some" approach the clearest, though.
contains better than indexOf ? I'd agree only if contains wasn't accepting any extra argument, which makes it even more (pointless?) similar to indexOf.
If it had only one incoming parameter, you could have ["maria", "marianne"].some(str.contains, str)
and win over all other examples. but
just the !=-1
or >-1
as reason to prefer contains? ... dunno, I think I
have 99 problems in JS related development, >-1
ain't one :-/
also, just for people not afraid of the tilde
["Maria", "Mariana"].some(e=>~a.indexOf(e));
yeah, you can use it ^_^
On 3/10/15, Andrea Giammarchi <andrea.giammarchi at gmail.com> wrote:
contains better than indexOf ? I'd agree only if contains wasn't accepting any extra argument, which makes it even more (pointless?) similar to indexOf.
If it had only one incoming parameter, you could have
["maria", "marianne"].some(str.contains, str)
and win over all other examples. but just the!=-1
or>-1
as reason to prefer contains? ... dunno, I think I have 99 problems in JS related development,>-1
ain't one :-/
Evidently.
I can only guess that str is a string. Strings don't have a contains method, nor was one proposed the call str.contains(str) inside of a call to some looks like a confused mistake.
not sure I understand what you say but ["maria", "marianne"].some(str.contains, str)
means ["maria", "marianne"].some(function (value) {return this.contains(value)}, str)
... no bind nor arrow function needed, the
function str.contains
is executed with str
as context per each
iteration. Is that confusing? 'cause that's how
some/every/forEach/map/filter work
Well the current ES6 .includes()
was before named .contains()
:
[String.prototype.includes] (
developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes#String.prototype.contains
)
But if Garrett Smith was trying to point out that .contains()
would be
better naming for the specific purpose of using an Array:
str.contains(["Mary", "Bob"])
then ok? maybe.
This is what I originally had in mind:
String.prototype.includesAll = function(arr, index, onlyOne){
return arr[onlyOne ? "some" : "every"](el => this.includes(el, index),
this);
}
But like Bergi said "denotative" the above with the onlyOne
argument
would also make this function denotative as well, and if you wanted to use
that argument you would have to specify the 0 as the index all the time.
So perhaps two functions
String.prototype.containsAll = function(arr, index) {
return arr.every(el => return this.includes(el, index), this);
}
String.prototype.contains= function(arr, index) {
return arr.some(el => return this.includes(el, index), this);
}
Origianlly I had the names includesAll
and includesOneOf
, but
contains
and containsAll
is more human readable.
Andrea Giammarchi said:
I'm still having hard time understanding what's the difference between
contains and the good old indexOf
Well like Garrett Smith said it is easier to read, and it gets rid of
.indexOf() > -1
which I consider a hack.
Why I consider a hack simply because .indexOf()
is used to return the
index, then adding > -1
or using a tilda ~
to make it a Boolean. Why?
Also mixing that with a some/every
function? and passing a callback, yea
I'd choose:
str.contains(["Mary", "Bob"])
over:
["Mary", "Bob"].every(el => el.indexOf(el) > -1);
//OR
["Mary", "Bob"].every(el => el.includes(el));
Also using indexOf()
if you want to start from a certain index would add
more complexity.
On 3/10/15, Edwin Reynoso <eorroe at gmail.com> wrote:
Hi Edwin -
Well the current ES6
.includes()
was before named.contains()
: [String.prototype.includes] ( developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes#String.prototype.contains )But if Garrett Smith was trying to point out that
.contains()
would be better naming for the specific purpose of using an Array:str.contains(["Mary", "Bob"])
then ok? maybe.
str.contains was Andrea's interpretation of my example. Nevermind that; let me try again...
You first asked about making String.prototype.includes take an array, check every item in the array, and return false if any array item is not present in the string, else return true. From that, you switched it around to array.every, to make sure every item was in the string.
names.every(name => str.includes(name));
So far so good...
That's essentially what Array.prototype.containsAll would do.
Array.prototype.containsAll(anotherArray)
You can split the string to get anotherArray.
names.every(str.split(/,\s*/));
I cannot explain what ES6 @@split does. The spec have gotten even farther away from how web developers understand the language.
The ECMAScript specification has always been complicated by internal specification mechanisms, and it was because of this obfuscation that I was able to have a bit of an edge on others. I was able to understand the difference between the confusingly same-named [[Prototype]] (an object's internal property) and fn.prototype (the property that every user-defined function gets by default), and that there implies that each user-defined function has both a [[Prototype]] (being Function.prototype) and a .prototype property. It's confusing, but I got it.
The new stuff in the spec, where there is not even String.prototype.split, but @@split is hard to understand. The ECMAScript 3 spec was already too hard for most developers. Things like missing RegularExpressionLiteral, the ActivationObject/VariableObject (which one is it?), PrimitiveValue being a number for Date objects, but where addition calls ToPrimitive with hint "string", and that gets passed to DefaultValue. It's hard. We need to work for the tech companies that steal your data and provide useless junk to the user. Call us rockstars or other insulting titles, but at the end of the day, I need to to is memorize those specs if I want to understand what I am doing in order to pay my rent. It can and should suck less.
ECMAScript 5 added complexity. ECMAScript 6's explanations and specification terminology seems too much for me. The spec shouldn't be so hard that programmers can't understand it. A good spec should serve as a reference for developers to go and look up how it works.
I can't say how I'd write it better because I haven't taken the time to grok it all. Nor do I plan to - life is too short.
On 3/10/15, Garrett Smith <dhtmlkitchen at gmail.com> wrote:
On 3/10/15, Edwin Reynoso <eorroe at gmail.com> wrote:
[...]
specs if I want to understand what I am doing in order to pay my rent.
It can and should suck less.
Let me rephrase that: I don't mean that the specification sucks - sitting down and trying to figure it out; reading the spec, for me, is not enjoyable work. The spec is hard and frustrating.
But I really do appreciate all the hard work and effort by Brendan, Allen, etc - you guys are all a lot smarter than I am. And ECMAScript is making a lot of improvements.
But I still don't like reading the spec.
There are times where I would like to check whether a string has every occurrence of certain strings/numbers:
So the way the above would work would be as an AND operation. Meaning having all of the instances of the array past in.
To use
String.prototype.includes
as an OR operation with the first parameter being an array, wouldn't be necessary because you can use a regular expression for that:As of right now
String.prototype.includes
called with an array as the first parameter will call.toString()
on the array resulting in the following:Pretty useless!!!
Now to achieve what I would like
String.prototype.includes
to accomplish with an array as the first parameter, I currently take the following approach: