Difference when using an object and an array being passed as this no apply using the Concat function

Asked

Viewed 85 times

2

I am studying Javascript and came across this difference when using an object and an array being passed as the this in the apply using the function concat. In the first case I use the this as an object, in the second case I used an empty array, and the difference is that it seems to be concatenating the object with the array that was passed as argument in the function, unlike when I pass only an empty array.

What would be the reason for this difference?

Example 01:

const test = Array.prototype.concat.apply(this, [
  [1, 2, 3, 4],
  [1, 2, 3, 4]
]);
console.log(test);

Output from example 01:

[{}, 1, 2, 3, 4, 1, 2, 3, 4]

Example 02:

const test = Array.prototype.concat.apply(
  [],
  [
    [1, 2, 3, 4],
    [1, 2, 3, 4],
  ]
);
console.log(test);

Output from example 02:

[1, 2, 3, 4, 1, 2, 3, 4]

1 answer

4

Initial concepts

First of all, it is important to know how to differentiate two concepts that are of paramount importance for understanding why your two examples above behave differently.

Although these two ideas have a very large relationship with the this (are, at bottom, almost the same thing, only in two different situations), it is important to know how to differentiate them:

Keyword this

To keyword this, in a very short way, will recover the value (usually an object) of the context in which it is running. In the global scope, the this will refer to the object window (or global, in Node.js).

So in your first example, where you do:

//                     Palavra-chave this
//                            ↓↓↓↓
Array.prototype.concat.apply( this , [
  [1, 2, 3, 4],
  [1, 2, 3, 4]
]);

Are you using the keyword this to recover the value the context in which it is being executed (in which case it will be the object window, since it is in the global scope) and pass as value this for the method concat.

Valor this

The value this (usually an object) is recovered within a context (such as the global scope or scope of functions) by keyword this - already mentioned. See an example:

const person = {
  name: 'Foo',
  greet: function() {
    // Estamos usando a -  para obter
    // o   relativo ao método `greet`.
    //           ↓↓↓↓
    const name = this.name;
    console.log(`Olá, eu sou o ${this.name}!`);
  }
};

person.greet(); // Olá, eu sou o Foo!

// Estamos modificando o   que o método `greet`
// recuperará ao utilizar a - . 
person.greet.apply({ name: 'Luiz' }); // Olá, eu sou o Luiz!

As you may have noticed above, it is very easy to confuse these two concepts, since they are so close. But, in short, see the value this as that which is returned by keyword this.

Also, as you may have seen, the value of this is easily modifiable using methods of a function such as apply, call or bind.

All three of these Function.prototype use the first argument to modify the value that the keyword this will recover when called. This argument is usually called an argument thisArg.

The answer in fact

Like any object, arrays too have methods, as the very concat. These methods expect to operate on some array. In implementing these methods, this array will be obtained through the value which will be returned by keyword this.

The language specification itself shows that the value this is used for this. If you are curious, see the first step of specification of Array.prototype.concat.

Knowing this, it is valid to say that the method concat (as well as the other methods of Array.prototype) expect to operate over an array. However, when this is not the case, some strange but predictable things happen.

In the case of concat, it is known that a new array is created, and the first elements of that new array are occupied by the array elements of the value this. If this value is not an array, it will simply take the first option of that array that was created.

First example

Therefore, in his first example, through the method apply, you are modifying the value this that the method concat will operate. Thus, instead of operating with an array, the object you passed it will be used in the argument thisArg of apply - in this case, the object is window, since you used the keyword this in the overall scope (which recovers window or global, in Node.js).

Let’s see a simpler example:

const person = { name: 'Bob' };

const arr = Array.prototype.concat.apply(person, [2, 3]);

console.log(arr);
console.log(arr[0].name); // Bob
console.log(arr[1], arr[2]); // 2 3

Note that the value we pass as this (through the apply) occupied the first position of the array created and returned by concat.

Second example

In the second example, as an empty array will be the value this of concat (since you passed it as argument thisArg of apply), nothing very unexpected, but the common behavior of concat will occur. Let’s see:

const arr1 = [].concat( 
  [1, 2, 3, 4],
  [1, 2, 3, 4]
);

// É o mesmo que isto:

const arr2 = Array.prototype.concat.apply([], [
  [1, 2, 3, 4],
  [1, 2, 3, 4]
]);

// Ou até o mesmo que isto:

const arr3 = Array.prototype.concat.call(
  [],
  [1, 2, 3, 4],
  [1, 2, 3, 4]
);

console.log(arr1);
console.log(arr2);
console.log(arr3);

This is all a mess caused by the method apply and the this in Javascript, which can take on several meanings depending on the context. Find out more about how they work.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.