Вы наверняка где-то читали, готовясь к техническому интервью: «в JavaScript все является объектом! Даже классы! Даже Функции!».
JavaScript — один из (если не «самый») самый популярный язык, используемый для веб-приложений и серверных приложений; это часть стандарта ECMAScript, и каждая новая спецификация вводит дополнительные функции, поддерживает ее в актуальном состоянии и добавляет новые интересные функции — однако рутинная работа, жесткая основа, которая делает JavaScript таким универсальным, правда ли, что это просто созданные объекты?

Истина и проста, и запутана. По своей сути JavaScript разделяет значения на два типа: примитивные значения и объекты. Хотя JavaScript часто кажется местом, где все значения действуют как объекты, существуют существенные различия и конкретные ситуации, когда эти различия имеют значение.

Во-первых, давайте сделаем примитивы и объект действительно четкими.

Примитивы или примитивные значения — это основные типы данных в JavaScript, которые не являются объектами и не имеют методов. JavaScript распознает семь примитивных типов данных: String, Number, BigInt, Boolean, Undefined, Null и Symbol. Если вы используете TypeScript, вы знаете, о чем я говорю (или даже PropTypes в React).

Хотя эти примитивные типы по своей сути не обладают свойствами или методами, JavaScript включает эквиваленты объектов — String, Number, BigInt, Boolean и Symbol — которые обертывают их соответствующие примитивные аналоги. Эта концепция называется «бокс».

let str = "Hello, World!"; // this is a string type
console.log(str.length); // 13 - this is a number type

В приведенном выше фрагменте кода str является примитивом строки, и когда мы ссылаемся на str.length , JavaScript автоматически "упаковывает" str во временный объект String, обращается к свойству length, а затем отбрасывает временный объект, создавая иллюзия примитива, действующего как объект. Но на самом деле это не так!

В отличие от примитивов, объекты в JavaScript представляют наборы свойств, каждое из которых является связью между ключом и значением.
А вот это мы все знаем. Значение может быть любым значением JavaScript, кроме null и undefined, и объект может представлять различные структуры данных, такие как массивы, функции и регулярные выражения, среди прочего (да, они все объекты!).

Объекты можно создавать с помощью:
- литералов объектов;
- конструкторов,
- метода Object.create.

Они очень похожи, но в чем тогда разница?

Наиболее важным отличием является то, что примитивы в JavaScript неизменяемы: хотя JavaScript позволяет вам обращаться к свойствам и методам примитивов, как если бы они были объектами, вы не можете изменять существующие свойства или добавлять новые к примитивам. Вот пример:

let str = "Hello, World!"; // initiate a string
str.property = "test"; // trying to add a property, as we would do in an obj
console.log(str.property); // undefined - not allowed, but no error

Здесь JavaScript не выдает ошибку, когда мы пытаемся присвоить новое свойство строковому примитиву str! Однако, поскольку примитивы неизменяемы, присваивание не вступает в силу, а последующий доступ к свойству возвращает undefined , так что эффект «я вас слышу, но нет, я этого делать не буду».

Все еще не уверены? Позвольте мне попытаться воздействовать на эти строки другим способом, притворившись, что они являются массивом (то есть объектом).

let greetings = "hello John";
greetings[0] = "H"; // Attempt to change the first letter to 'H'
console.log(greetings); // "hello", not "Hello"

Другая уникальная характеристика примитивов заключается в том, что они сравниваются по значению, а не по ссылке, как это происходит с объектами. Это может быть более интуитивно понятно, если я спрошу вас «эта кружка такая же, как эта», вы проверите две вещи на моей руке и сравните их. Это интуитивно, верно? Однако в JavaScript, если вы сделаете то же самое, сравнивая два свойства, как в следующем примере, ответ будет false!

let person1 = { age: 18};
let person2 = { age: 18};
console.log(person1 === person2); // false

Они идентичны! Однако мы сравниваем ссылку на объект (ячейки памяти) вместо его свойств, и вот в чем хитрость. Однако сравнение двух примитивов таким же образом приведет к другому результату.

let myAge = 22; // I wish!
let yourAge= 22;
console.log(myAge === yourAge); // true

Это означает, что когда вы сравниваете два примитива с помощью ===, JavaScript проверяет, имеют ли они одинаковое значение.

Время делать выводы

Итак, резюмируя:

  1. Примитивы являются неизменяемыми и имеют простые типы данных, в то время как объекты изменяемы и могут быть более сложными.
  2. Примитивы сравниваются по значению, а объекты сравниваются по ссылке.
  3. У примитивов нет свойств или методов, в отличие от объектов. Однако JavaScript позволяет примитивам получать доступ к методам их объектов-оболочек, создавая иллюзию того, что у примитивов есть методы (упаковка).

И теперь вы знаете, на что ответить в следующий раз, когда на собеседовании вам зададут этот каверзный и интересный вопрос 😉