Данные, которыми мы оперируем в своих программах, могут обладать важными свойствами — например, у строк есть длина. Как вы увидите далее, это свойство очень важно для реализации алгоритмов, связанных с преобразованием строки (как пример — переворот строки). Как узнать длину строки? Во многих языках длина строки вычисляется с помощью специальной функции и выглядит это примерно так:
import { length } from './hexlet-basics/string.js';
const name = 'Robb';
console.log(length(name)); // => 4
В JavaScript свойства встроены прямо в язык. Они указываются через точку сразу после переменной (или константы):
const name = 'Robb';
const len = name.length;
console.log(len); // => 4
Свойства связаны с данными, у которых они берутся. Для стандартных типов все свойства описаны в документации, как например, у строк. При этом у чисел вообще нет свойств.
JavaScript позволяет обращаться к свойствам, которые не существуют (например, при опечатках). В таком случае их значением является undefined
:
const name = 'Robb';
console.log(name.whatIsThat); // => undefined
Вопрос для самопроверки. Что распечатает код console.log(name[name.length])
для name
, определенного выше? Почему ответ такой?
Методы
В JavaScript у данных есть не только свойства, но и методы. Методы - это функции, которые находятся внутри свойств. Это означает, что метод можно вызвать как функцию, но при этом он работает как свойство и вызывается через точку.
const name = 'Robb';
const upperName = name.toUpperCase();
console.log(upperName); // => ROBB
Встроенные методы всегда оперируют теми данными, с которыми они связаны. Метод .toUpperCase()
возвращает такую же строку, но преобразуя все символы в верхний регистр. Методов у данных обычно значительно больше, чем свойств, например, для строк их несколько десятков. В документации, на первый взгляд, они описаны немного странно: String.prototype.toLowerCase(). Это описание раскрывает некоторые внутренние детали реализации, которые сейчас не важны, да и мы не изучили всей необходимой базы для разговора о прототипах.
Методы есть и у чисел:
const temperature = 22.93;
// Округление до одного знака после запятой
const roundedTemperature = temperature.toFixed(1);
// Метод возвращает строку, которая содержит преобразованное число
console.log(roundedTemperature); // => 22.9
// Напрямую можно вызывать так
(22.93).toFixed(1); // 22.9
Технически всё несколько сложнее. Методы есть не у самих чисел, а у данных (объектов) типа Number. Числа, записанные в переменные или константы, автоматически преобразуются к данному типу во время обращения к ним, в это время происходит так называемый boxing.
Возникает закономерный вопрос: зачем нужны методы, почему не просто функции? С числами ситуация еще сложнее. Часть операций реализована в виде методов самих чисел, например, .toFixed()
, а еще большая часть — в виде методов, доступных через Math
.
Есть две причины, почему так сделано:
- Исторически так сложилось. JavaScript разрабатывался слишком быстро и поэтому не все было продумано хорошо.
- Далеко не все функции имеют отношение к конкретному значению. Возьмем для примера
Math.min()
. Эта функция находит минимальное число среди всех, которые ему были переданы. Эту функцию нелогично делать методом конкретного числа, например, так —(1).min()
. Она не имеет никакой связи с конкретным числом
С другой стороны, функции, работающие с конкретным числом, для единообразия должны быть реализованы как методы. К таким функциям относится получение модуля числа. То есть вместо такого вызова Math.abs(-10)
, логично иметь такой: (-10).abs()
.
Что касается методов в целом, то не все так однозначно. Есть языки, в которых методов нет и там все прекрасно, есть языки, где методы — это основной способ работы с функциями. JavaScript — язык, в котором прижились оба подхода, в нем активно используются как обычные функции, так и методы. О плюсах и минусах подобных подходов подробно рассказывается в курсах, посвященных ООП.
Неизменяемость
Что напечатает на экран последний вызов?
const name = 'Tirion';
console.log(name.toUpperCase()); // => TIRION
console.log(name); // => ?
Ответ на этот вопрос зависит от того, как вы поняли урок про неизменяемость примитивных типов данных. Вызов метода .toUpperCase()
возвращает новое значение, в котором все буквы преобразованы в верхний регистр, но он не меняет (и не может этого сделать) исходную строку. Поэтому внутри константы (или переменной — это не важно) окажется старое значение: 'Tirion'
. Эта логика справедлива для методов всех примитивных типов. Более того, попытка изменить значение свойства этих данных ни к чему не приведет:
const name = 'Tirion';
console.log(name.length); // => 6
name.length = 100;
console.log(name.length); // => 6
Вместо изменения значения можно заменить значение. Для этого понадобятся переменные:
let name = 'Tirion';
name = name.toUpperCase();
console.log(name); // => TIRION
Свойства и методы как выражения
Свойства и методы — такие же выражения, как переменные, константы или вызовы функции, а значит, их можно всячески комбинировать.
Использование в операциях:
const name = 'Shaya';
name.length + 5; // 10
`hi, ${name.toUpperCase()}!`; // hi, SHAYA!
Использование в параметрах функций:
const name1 = 'Robb';
const name2 = 'Shaya';
console.log(name2.length); // => 5
console.log(name2.toLowerCase()); // => shaya
console.log(Math.min(name1.length, name2.length)); // => 4
https://replit.com/@hexlet/js-basics-properties-method

Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты
- Статья «Как учиться и справляться с негативными мыслями»
- Статья «Ловушки обучения»
- Статья «Сложные простые задачи по программированию»
- Урок «Как эффективно учиться на Хекслете»
- Вебинар «Как самостоятельно учиться»