Язык программирования javascript — работа примитивов JS

Язык программирования javascript

Язык программирования javascript (JS) — это мультипарадигменный язык программирования. Обучающая статья посвящена языку программирования javascript (JS), хотя вернее будет сказать – описывает работу примитивов javascript. В материале рассматриваются основные принципы работы примитивных типов данных в javascript и, в дополнение, то, что происходит под прикрытием. С использованием методики принуждения примитивов к объектам был выполнен анализ работы JS Engine и свойств примитивов. Автором была изучена способность назначать свойства объектов перед их примитивными аналогами.

На основании полученных данных установлена способность назначать свойства — почти единственное преимущество объектов. Если javascript обнаруживает попытку назначить свойство примитиву, Js Engine приведет его к объекту. Но, этот новый объект не имеет ссылок и сразу станет кормом для сборки мусора. Хорошее понимание примитивов и того, что происходит «под капотом», является важным шагом на пути к более глубокому изучению языка.

Язык программирования javascript — примитивы javascript и их тайная жизнь

Язык программирования javascript

Предположу, что для вас будет в новинку факт того, что в JavaScript, взаимодействуя со строковыми, числовыми или логическими примитивами, вы попадаете в скрытый мир Зазеркалья.

Язык программирования javascript — типы данных
Язык программирования javascript

Логические, числовые и строковые примитивы могут быть обернуты их объектными аналогами. Такие объекты станут экземплярами Boolean, String и Number конструкторов объектов соответственно.

Пример использование конструктора new:

typeof new Boolean(false); // return «object»
typeof (new Boolean(false)).valueOf(); // return «boolean»
typeof false; //»boolean»
typeof Boolean(false); // return «boolean»

typeof new String(«word»); // return «object»
typeof (new String(«word «)).valueOf(); // return «string»
typeof » word «; // return «string»
typeof String(«word «); // return «string»
typeof 321; // return «number»

typeof Number(321); //return «number»
typeof new Number(431); // return «object»
typeof (new Number(431)).valueOf(); // return «number»

Если примитивы не имеют свойств, почему «string» .length возвращает значение?

Язык программирования javascript
Все просто – JavaScript насильно принуждает примитив стать объектом. В этом случае строковое значение приводится к строковому объекту для доступа к свойствам наподобие length (длина). Строковый объект используется исключительно на доли секунды, после чего приносится в жертву богам мусоросборки.

Язык программирования javascript

a; //»cba»
typeof a; //» return string» (still a primitive)
b; //»cba»
typeof b; // return «object»

Идем дальше. Как и во всех значимых работах, мы выворачивали наизнанку устоявшееся положение дел, не позволяя объекту собирать мусор, пока присутствует b.

(! В строгом режиме неуловимое существо устраняется)

Безусловно, существуют варианты проверить тип объекта, не затрагивая сборку мусора:

Язык программирования javascript

(123).toString(); // return “object»

Здесь можно отметить однозначный факт – примитивы имеют доступ ко всем свойствам (включая методы), определенным соответствующими конструкторами объектов.

 

JavaScript и valueOf

Язык программирования javascript

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

alert(myCat);
let result = 2 + myCat;

Подведем черту. Если выражение намекает на необходимость строки, вызывается toString, в противном случае – valueOf. Если один из методов возвращает не примитив, шанс получает другой. В примерах выше ожидается, что myCat будет и строкой, и числом, поэтому они будут оцениваться как:

alert(myCat.toString()); //интерпретатор ожидал строку
let result = 2 + myCat.valueOf(); //ожидал число

[См. ECMA 5 главу 8.12.8 для полного алгоритма. Помните, что [[DefaultValue]], hint и ToPrimitive являются внутренними конструкциями]

Основываясь на этих правилах, вполне логично, что valueOf будет возвращать не строковое представление объекта.

Существует возможность воспользоваться значением valueOf для создания сжатого синтаксиса текущей даты, выраженной в миллисекундах:

(new Date()).valueOf(); //1588962243724 (date in ms)
+ new Date();//15889622488
+ 95(ожидается нестроковый примитив после знака+)
+new Date; //1588962256511 (то же самое, но даже более короткий синтаксис)

Если есть необходимость накатывать собственные показатели профилирования, можно воспользоваться информацией, представленной далее.

Большинство других реализаций valueOf по умолчанию не интересны:

Boolean(true).valueOf(); //true
Number(‘123’).valueOf(); //123
«aaa».valueOf(); //»aaa»

Но ведь куда интереснее определить свои собственные значения реализаций, не так ли?

var toDollarRate = {
rubles: 0.014,
pounds: 1.5

}

var Drink = function(name, cost, currency) {
this.name = name;
this.cost = cost;
this.currency = currency;
}

Drink.prototype.costInDollars = function() {
return this.cost * (toDollarRate[this.currency] || 1);
}

var boddingtons = new Drink(«Boddingtons», 2.50, ‘pounds’);
var peroni = new Drink(«Peroni», 3.50, ‘rubles’);
var anchorSteam = new Drink(«Anchor Steam», 3.50, ‘dollars’);

Drink.prototype.valueOf = Drink.prototype.costInDollars;
‘$’ + (boddingtons + peroni + anchorSteam).toFixed(2); //$7.30

Теоретически, приводя объект в логическое значение, он может представлять запрос, потенциально заканчивающийся как положительным, так и отрицательным результатом.

var SystemRequest = function(name) {
this.name = name;
}

SystemRequest.prototype.run = function() {
//симуляция результатов теста
this.success = Math.random(1)>0.5;
return this;
}

SystemRequest.prototype.valueOf = function() {
return this.success;
}

var request1 = new SystemRequest(‘request1’);
var request2 = new SystemRequest(‘request2’);
var request3 = new SystemRequest(‘request3’);

request1.run() + request2.run() + request3.run(); //2
request1.run() + request2.run() + request3.run(); //1
request1.run() + request2.run() + request3.run(); //3 (all passed!)

Здесь valueOf возвращает логическое значение, но в инструкциях окончательного выполнения используется конкатенация для преобразования логических значений в числа (1 для передачи, 0 для отказа).

Неплохим подспорьем может служить переопределение valueOf. И совершенно не имеет значения, использовать его так, или нет, знание того, как и почему JavaScript выбирает методы по умолчанию toString и valueOf, поможет вам лучше узнать код.

Язык программирования javascript — могут ли эти объекты быть приведены к значениям?

Вполне. Объекты этого типа являются не более чем обертками, их значение – примитив, который они обертывают, и чаще всего приводят к этому значению по мере необходимости.

//объект приведен к примитиву
var Twelve = new Number(12);
var fifteen = Twelve + 3;
fifteen; //15
typeof fifteen; //»number» (примитиву)
typeof Twelve; //»object»; (все еще объект)

//другой объект приведен к примитиву
new String(«salli») + «slet»; //» sallister»

//объект не приведен (потому что оператор typeof может работать с объектами)
typeof new String(«salli «) + » slet «; //»object slet »

Увы, Boolean объекты приводятся не так легко. И, чтобы провернуть нож в ране, Boolean объект оценивается как true, если его значение не равно null или undefined. Можно воспользоваться:
if (new Boolean(true)) {
alert(«false???»);
}

Чаще всего имеет смысл явно запрашивать логические объекты для их значения. Следующее поможет определить, является значение «truthy» или «falsey»….

var empty = «»;
new Boolean(empty).valueOf(); //false

… но на практике легче сделать так…

var empty = Boolean(«»);
empty; //false

… или даже так …

var empty = «»;
!!empty; //false

Язык программирования javascript — позволяет ли принуждение присваивать значения примитивам?

Нет

const monthNum = «october «;
primitive.monthNum = 11;
primitive.monthNum; //undefined;

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

Вот псевдокодовое представление того же примера, чтобы

проиллюстрировать, что на самом деле происходитconst primitive = «october»;
primitive.monthNum = 11;
// новый объект, созданный для установки свойства(new String(«october «)). monthNum = 11;

primitive.monthNum;
// еще один новый объект, созданный для получения свойства(new String(«october»)).monthNum; //undefined

Заметим, все это не только бесполезно, но и довольно иррационально.

В результате

Оказывается, что способность назначать свойства — почти единственное преимущество объектов перед их примитивными аналогами. Строки, логические значения и числа имеют конкретные и четко определенные цели.

Тем не менее хорошее понимание примитивов и того, что происходит “под капотом” когда вы взаимодействуете с ними, является важным шагом на пути к более глубокому изучению языка.

0 0 голоса
Оценка статьи
Подписаться
Уведомить о
guest

0 Комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
Этот сайт использует куки для улучшения вашего просмотра. Ваши личные данные находятся в безопасности