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.