I'm a beginner of JavaScript.
I am really curious about how the code works..!!
Does anyone could explain how the code down below works, please?
It seems different from just 'abc'.toUpperCase();
'aaa'['toUpperCase'].apply('abc'); // ABC
I'm a beginner of JavaScript.
I am really curious about how the code works..!!
Does anyone could explain how the code down below works, please?
It seems different from just 'abc'.toUpperCase();
'aaa'['toUpperCase'].apply('abc'); // ABC
Well, it's equivalent to 'aaa'.toUpperCase.apply('abc'), if that helps.
In JavaScript, objects are really just associative arrays. The dot notation foo.bar is just a convenience shorthand for foo['bar'] that works when the array key string (bar in this case) has the form of an identifier - all letters plus maybe some underscores, and digits as long as it doesn't start with one.
So when you call a method on an object, you're really just looking up the value stored in the array slot whose key is the method name. For methods, that value is a function, or "closure", which you can then call using the () syntax.
But for method names, the slot on the object itself is usually actually empty! That causes Javascript to look it up on the prototype object shared by all objects of the same type; this is how JavaScript's prototype-based inheritance works. In your case, the string 'aaa' doesn't actually have anything stored under the key toUpperCase, so JS looks at the String prototype to find it. That way all Strings have a common set of methods you can call on them – without having to store copies of those methods inside every string in your program.
By itself, 'aaa'.toUpperCase is just another inert value. It happens to represent a function (or closure), but until you do something to cause it to run, it's no more active than a number or string. You can pass it around to other method calls, store it in other variables or properties, do whatever you want with it.
Once you do call it, it will get an invocant – the value of this inside the method call – that depends on where the call is in relation to the property lookup. Usually you just call a method immediately in the same expression where you retrieve it from an object, in which case the invocant is that same object. This behavior is more JavaScript syntax magic at work; foo.bar() is effectively a shortcut for foo.bar.apply(foo) that keeps you from having to repeat the object expression foo.
If you make a copy of the method and call it without an explicit object reference, it will inherit the value of this from the calling context. And likely complain that the referenced object is not the expected type.
But methods themselves are also objects, and they have their own methods that you can call on them, including one called apply that lets you call a method with a passed-in object as invocant. That's what your code does - looking up the method via 'aaa' but then actually calling it on 'abc' instead.
Firstly, it's actually just equivalent to ''.toUpperCase.apply('abc'). The content of the string on the left of toUpperCase doesn't make a difference. What does this mean? toUpperCase is a function available on every string in JavaScript. And apply is a function available on every function in JavaScript. It can be used to change the value of this inside a function.
So, if you split your code this way, you understand what's happening:
const upperCase = ''.toUpperCase;
upperCase.apply('abc'); // ABC
It so happens that String#toUpperCase uses the value of this inside it to convert to an uppercase.
From docs:
All String instances inherit from String.prototype. Changes to the String prototype object are propagated to all String instances.
So all strings inherits a series of methods and properties, and since you can access properties with dot or square notation.
Therefore this code:
'aaa'['toUpperCase'].apply('abc'); // ABC
Equivalent to this:
'aaa'.toUpperCase.apply('abc'); // ABC
and also equivalent to:
String.prototype['toUpperCase'].call('Hello')
// or
String.prototype.toUpperCase.call('Hello')
apply and also call are functions inherited from Function.prototype and allow to execute functions in Javascript.
Firstly, 'aaa' is a string, so you can apply any methods for string.
'aaa'['toUpperCase'] will return a function call toUpperCase. You can use any other method for string like charAt or even attribute like length. Thus 'aaa'['toUpperCase'].apply('abc'); will return 'ABC' as a final result
First, 'aaa'['toUpperCase'] is equvelent to 'aaa'.toUpperCase, basically, 'aaa' is a string literal, every string has a toUpperCase property which is a function.
Then, apply, it's a method available for all functions. It has the following signature yourFunction.apply(thisArg, [argsArray]) which calls a function with a given this value, and arguments provided as an array. Basically, you can think it as thisArg.yourFunction(argsArray)
So, when you call 'aaa'.toUpperCase(), this is 'aaa'. But when you call 'aaa'.toUpperCase.apply('abc'), this now is 'abc', so you can think it as 'abc'.toUpperCase(), so the result is 'ABC'
Based on the above analysis,'aaa'['toUpperCase'].apply('abc'); returns 'ABC'.