Язык программирования 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”

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

Это будет интересно:   Компания Kano создала новый сборный планшетный ПК для обучения детей

 

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, поможет вам лучше узнать код.

Это будет интересно:   Рейдерский захват китайского ARM завёл в тупик: кто прав, а кто виноват?

Язык программирования 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

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

В результате

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

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

Инженер Программист ИМТО. Специалист в области веб и разработки программного обеспечения, науке о данных, креативной концепции, методологии Agile & Scrum.

Подписаться
Уведомление о
guest
0 Комментариев
Встроенные отзывы
Смотреть все комментарии
0
Присоединяйтесь к обсуждению статьи!x
()
x
Этот сайт использует куки для улучшения вашего просмотра. Ваши личные данные находятся в безопасности