3

I call concat() on a string as shown below:

> "1".concat("2","3")
< "123"

Now I want to do this for the case where I have an array of strings to concat togther. But it doesn't do what I expect:

> "1".concat.apply(["2","3"])
< "2,3"

Not only is the first element missing, but a comma has been inserted between the two elements passed, like it was converting the argument in apply to a string and then returning that instead.

How can I use apply? I can't use String.prototype.concat.apply because the first argument is actually a variable which could be string or array. I would rather not do some awful hack where I have to detect the type and then have a separate statement for each possible type the argument could be.

To be clear, I am trying to implement a function concat() which works for any first argument type which makes sense (e.g. string or array). So far it looks like this, but is not working:

function concat(x) {
    var args = Array.prototype.slice.call(arguments,1)
    return x.concat.apply(args)
}
Michael
  • 9,060
  • 14
  • 61
  • 123

5 Answers5

6

The first argument of apply is the context, which needs to be the string. You'd use

const arr = ["2","3"];
console.log("1".concat(...arr));
console.log(String.prototype.concat.apply("1", arr));
console.log("".concat.apply("1", arr));

In your particular case, I'd recommend to use rest/spread syntax:

function concat(x, ...args) {
    return x.concat(...args);
}

or in ES5

function concat(x) {
    var args = Array.prototype.slice.call(arguments, 1);
    return x.concat.apply(x, args);
//                        ^
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • 1
    excellent answer. i'm so used to putting "null" or "this" as the first argument to apply, and it confused me when that started throwing errors so I removed it and found it didn't seem to mind (aside from returning the wrong result!) Now it is obvious to me that what is happening is the first argument is being convert to a string and concatenated with nothing. – Michael Mar 06 '18 at 20:25
  • minification tools like uglify will barf on the ellipsis `...arr`. This may or may not be a consideration. – S. Imp Mar 06 '18 at 20:29
  • 1
    The spread approach presumably has implications for large arrays? – Oliver Charlesworth Mar 06 '18 at 20:29
  • @OliverCharlesworth No other implications than `apply` has. – Bergi Mar 06 '18 at 21:55
  • 1
    @S.Imp You should use a modern ES6-compatible minification tool then. I guess a more important consideration would be whether you need to support pre-ES6 browsers :-) – Bergi Mar 06 '18 at 21:55
  • @bergi feel free to suggest one. – S. Imp Mar 07 '18 at 00:05
  • 1
    @S.Imp I cannot recommend any since I personally never used one, but [Google suggests a few](https://www.google.com?q=es6+minifier) – Bergi Mar 07 '18 at 00:14
1

When using a native function in JavaScript I recommend reading the MDN first.

By calling "1".concat you get the raw function of the string object, thus losing the context. If you want to call a function using apply, the first parameter is an object the function uses as its this object or context.

So "1".concat.apply(["2", "3"]) is semantically equivalent to (""+["2", "3"]).concat().

I guess what you want to do is the following:

var unboundConcat = String.prototype.concat;
return unboundConcat.apply("1", ["2", "3"]);
Timm
  • 1,005
  • 8
  • 20
0

Use the prototype String.prototype and join the array values using the function .join().

console.log(String.prototype.concat("1", ["2","3"].join('')))
Ele
  • 33,468
  • 7
  • 37
  • 75
0

If you want to use the concat according to the String or Array prototype, you can use Object.getPrototypeOf()

var stringOrArray = "1"

   
console.log(Object.getPrototypeOf(stringOrArray).concat.apply(stringOrArray, ["2","3"]))

stringOrArray = ["1", "5"]

   
console.log(Object.getPrototypeOf(stringOrArray).concat.apply(stringOrArray, ["2","3"]))
juvian
  • 15,875
  • 2
  • 37
  • 38
0

The first argument to apply is the context, or this.

in ES6:

  • aORs = array or String
  • concatWith = what you are concatenating the array or string with

    let concat = (aORs) => (concatWith) => aORs.concat(concatWith);

let concat = (aORs) => (concatWith) => aORs.concat(concatWith);

console.log(
  concat(["a", "b"])(1)
); 
//["a", "b", 1]

console.log(
  concat("1")(" 2")
);
// "1 2"

ES5

function concat(aORs) {
 return function(concatWith) {
   return aORs.concat(concatWith);
 }
}

function concat(aORs) {
  return function(concatWith) {
    return aORs.concat(concatWith);
  }
}

console.log(
  concat("1")("abc")
);

console.log(
  concat([1, 2, 3])("abc")
);
zfrisch
  • 8,474
  • 1
  • 22
  • 34