Methods are functions stored in object properties. If this is the case, then why does this code works:
'hexlet'.toUpperCase(); // "HEXLET"
From this code, one might draw the erroneous conclusion that a string is also an object, but that's not the case. In JavaScript, strings, logical values, null, and numbers are implemented as primitive values with no methods. On the other hand, each such type has its own constructor that boxes the primitive type with a wrapper object:
typeof 'hexlet'; // "string"
const name = new String('hexlet');
typeof name; // "object"
console.log(name); // "hexlet"
JavaScript automatically boxes primitives into relevant objects when it encounters method calls on them (and then automatically unboxes them). In other words, all the methods we call on strings the String
constructor prototype contains. The same goes for all other types:
// Manual boxing of primitives
const number = new Number(1);
number.toString(); // "1"
const bool = new Boolean(true);
bool.toString(); // "true"
// Automatic boxing
const one = 1;
// Boxing takes place when calling a method
one.toString(); // "1"
// Note that this code will end with an error:
// 1.toString();
// JS expects the number to continue after the dot
// And this is how (1).toString() will work;
const yes = true;
// During the call, boxing takes place
yes.toString(); // "true"
What's interesting is how the unboxing happens. To do this, JavaScript automatically calls valueOf()
:
const number = new Number(100);
// It can be called by yourself
number.valueOf(); // 100
// It's also called as a result of various operations on the object
const newName = `${number} is a big number`; // "100 is a big number!"
Unlike boxing, unboxing is performed for absolutely all objects. This allows you to define valueOf()
yourself:
const words = ['Hello'];
const helloBuilder = (string) => words.push(string);
const build = () => words.join(' ');
helloBuilder.valueOf = () => build();
helloBuilder('from');
helloBuilder('valueOf');
console.log(helloBuilder == 'Hello from valueOf'); // true
Various libraries like moment.js use this to convert the date (as an object) into a value (timestamp):
const date = moment(); // returns an object describing the current date
// you can do all sorts of things with this date
date.startOf('day').fromNow(); // "a day ago"
// The trick is that the `+` operator causes unboxing
// valueOf returns the current timestamp
+date; // 1578624487377
Although it works, many developers discourage this approach. It looks more like a hack than good code.
Recommended materials
Are there any more questions? Ask them in the Discussion section.
The Hexlet support team or other students will answer you.
For full access to the course you need a professional subscription.
A professional subscription will give you full access to all Hexlet courses, projects and lifetime access to the theory of lessons learned. You can cancel your subscription at any time.