void
new
this
Мой более-менее серьезный путь в программировании начался с написания программ на языке C#, иногда я пробовал писать на JavaScript, и то и дело впадал в ступор в таких ситуациях, когда неверно указывал имя переменной и узнавал об этом спустя много много лет час отладки, так как со мной рядом не было моего компилятора, который бы меня выручил в трудную минуту. Через некоторое время, помимо C# я начал писать много кода на JavaScript и в настоящее время могу делать это без особых трудностей, меня больше не смущает неявное приведение типов и динамическая типизация.
В данной статье я бы хотел систематизировать свои базовые знания об этих языках и рассмотреть их сходства и различия. Данная статья может служить руководством для C# разработчиков, которые хотят изучить JavaScript и наоборот. Также хочу заметить, что в данной статье описываются возможности клиентского JS, так как опыта разработки на Node.js у меня нет. Итак, если вы все ещё не потеряли интерес - приступим.
В каждой программе для избежания конфликтов в именах переменных, функций, классов или других объектов мы объединяем их в некоторые области. Таким образом, если две разные области будут содержать элементы с одинаковыми именами, конфликта не произойдет.
В C# для разбиения программы на части используются пространства имен. Для их объявления используется ключевое слово namespace
. Например, если мы хотим создать набор компонентов пользовательского интерфейса, то логично поместить их все в одно пространство имен, например, Components
. При этом принято чтобы пространство имен имело следующее именование [AssemblyName].[DirectoryName].[DirectoryName].[...]
. В каждом файле класс компонента пользовательского интерфейса необходимо поместить внутрь пространства имен:
Содержимое файла ComboBox.cs
:
Для того, чтобы начать использовать компоненты необходимо импортировать их из пространства имён следующим образом using AssemblyName.Components
. При данном способе подключения одной строкой мы импортируем все объекты в текущий файл.
В JS для этих же целей применяются ES-модули. При их использовании мы в какой-то степени эмулируем поведение пространств имен написанием дополнительного кода. Рассмотрим тот же пример с библиотекой компонентов. Допустим у нас есть папка Components
, которая содержит компоненты пользовательского интерфейса ComboBox.js
, Checkbox.js
, Button.js
и тд. Для того чтобы получить схожее поведение по сравнению с пространством имен в папке Components
необходимо создать файл index.js
, который будет содержать следующий код:
Для того, чтобы использовать данные компоненты необходимо импортировать их в текущий файл. Это можно сделать следующим образом: import * as Components from './../Components'
, после ключевого слова from
нам необходимо указать путь к папке, в которой находятся все описанные компоненты.
var
Как известно C# является строго типизированным языком программирования, поэтому при объявлении переменной компилятору должен быть известен её тип, для этого обычно он указывается перед её именем.
Но мы также можем сказать компилятору, что он должен вывести тип самостоятельно из выражения, стоящего после знака присваивания. Это стало возможно благодаря введению в версии C# 3.0 ключевого слова var
.
С помощью var
мы можем создавать объекты анонимного типа:
В JavaScript для объявления переменных также можно использовать ключевое слово var
, однако, в отличии от C# областью видимости данных переменных будет вся функция или объект window
, если переменная была объявлена вне функции.
Хоть у вас и есть возможность объявлять переменные с помощью var
в JavaScript, но сейчас этого делать не рекомендуется, после выхода стандарта ES6 было добавлено ключевое слово let
, которое также позволяет объявлять переменные, но его преимуществом заключается в том, что их областью видимости будет являться блок, в котором они объявлены, а не вся функция.
Как в C#, так и в JavaScript для объявления константного поля используется ключевое слово const
. Правда стоит отметить, что понятие константы в данном случае является различным для данных языков.
В C# константой называется выражение, которое может быть полностью вычислено на этапе компиляции, т.е. константы могут быть числами, логическими значениями, строками или нулевыми ссылками..
В JavaScript значение константы также нельзя изменять, однако нет ограничений, накладываемых на значение как в языке C#, ей можно присваивать любые значения/объекты/массивы. Однако, если в константу присвоен объект, то от изменения защищена сама константа, но не свойства внутри неё:
void
Во время написания данной статьи, я экспериментировал в консоли с функциями и по првычке начал описывать функцию как в C# void SomeFunction...
, и для меня было большой неожиданностью, когда я узнал, что в JavaScript есть ключевое слово void
. Как оказалось void
в JavaScript является унарным оператором, который вычисляет значение операнда, затем отбрасывает его и возвращает undefined
.
Таким образом, можно сказать, что использование void
явно указывает отсутствие возвращаемого значения, подробнее с примерами его использования вы можете ознакомиться в следующей статье статье.
В C# void
не является оператором, однако по сути имеет схожее значение. Здесь он обозначает отсутствие возвращаемого значения функции:
Однако, как можно заметить в примере выше, void
стоит в том месте, где обычно указывается тип возвращаемого значения, и это не случайно, ведь в C# void
также является типом.
void
в качестве типа может использоваться только в небезопасном контексте при работе с указателями.
new
В JavaScript ключевое слово new
является оператором, и используется привычным для многих C-подобных языков образом - для создания объекта.
В C# new
может использоваться для следующих целей:
Первый случай аналогичен применению new
в JavaScript.
В каждом языке имеются типы данных - примитивы, на основе которых строятся другие типы данных, давайте рассмотрим типы данных предоставляемые нам в C# и JavaScript.
Примитивные типы С#:
sbyte
, short
, int
, long
byte
, ushort
, uint
,ulong
char
char
float
, double
decimal
bool
Базовый классом является Object
.
Для JS:
Примитивные типы данных:
number
string
boolean
null
undefined
symbol
Базовым типом является Object
.
После изучения примитивов обоих языков можно придти к следующим выводам:
number
;char
, вместо него стоит использовать тип string
;Object
;null
и undefined
выделены в отдельные типы, в то время как в C# null
- это ключевое слово обозначающее отсутствие значения.symbol
, который используется в основном внутри самого стандарта JavaScript, для того чтобы иметь возможность добавлять новый функционал без конфликта с существующей кодовой базой.Как правило, сейчас все больше приложений, в которых необходимо выполнять обработку данных на клиенте, для чего требуется большая точность в вычислениях. В настоящее время в JavaScript отсутствует встроенная возможность работы с большими числами, однако в недалеком будущем планируется добавить новый тип BigInt
. Для решения аналогичных задач в C# имеется класс System.Numerics.BigInteger
.
Проверка типа является достаточной типичной операцией для большинства языков программирования. Основываясь на типе, мы можем выполнять различные действия. Например, рассмотрим пример из жизни: вы слышите звонок в дверь, если к вам пришел пьяный сосед (объект с типом Пьяный Сосед) чтобы занять денег, то вы вряд ли откроете ему дверь, но если за дверью ваш лучший друг (объект с типом лучший друг), то вы не задумываясь впустите его в квартиру. C# и JavaScript также предоставляют средства для проверки типа объектов.
typeof
Для получения информации о типе как в C#, так и в JavaScript имеется оператор typeof
. Давайте рассмотрим принцип его работы в обоих языках:
В С# оператор typeof
применяется к типу и возвращает объект класса Type
, который содержит всю информацию о типе.
В JS typeof
возвращает строку, указывающую тип операнда.
В примере выше можно заметить некоторые особенности работы данного оператора. Кажется логичным, если выражение typeof new Animal()
возвращало бы строку 'Animal'
, a typeof [1,2,3]
- строку Array
, однако как бы ни было парадоксально, результатом в обоих случаях является 'object'
. Также в связи с тем, что классы в JS являются оберткой над функциями, то выражение typeof class C {}
вернет 'function'
вместо 'class'
. Ещё одним интересным фактом является то, что выражение typeof null
вернёт 'object'
. В JavaScript данный оператор имеет большой недостаток: все не примитивные объекты для него на одно лицо, все они имеют один тип object
.
Стоит заметить, что в JavaScript typeof
можно применять к чему угодно: объектам, функциям, классам и т.д.. В C# данный оператор применяется лишь к типам.
Помимо получения информации о типе, порой бывает полезно проверить принадлежность объекта к определенному типу.
В C# для данных целей имеется оператора is
.
В JavaScript для того, чтобы выяснить к какому типу принадлежит объект необходимо использовать оператор - instanceof
.
Практически повсеместно, для того чтобы не получить Null reference exception
, перед использованием переменной мы проверяем её на null
, а в случае с JavaScript, ещё и на undefined
.
В C# мы постоянно видим подобный код:
В JavaScript данную конструкцию можно записать несколько короче. Связано это с тем, что в отличии от C#, в JavaScript множество значений кроме false
при приведении типов также расцениваются как false
:
null
undefined
0
NaN
(not a number)Таким образом, приведенный выше код на C# можно записать следующим образом:
или
В связи с тем, что проверки на null
происходят повсеместно, в C# 6.0 был добавлен Null Propagation Operator .?
.
Код на языке C#:
С его помощью данный участок кода можно переписать следующим образом:
В JavaScript обычно делают следующим образом:
Ещё одной частой операцией является установка значений по-умолчанию, с версии 2.0 в C# появился Null Coalescing Operator - ??
.
Следующие две строки кода на C# являются эквивалентными:
В JavaScript подобную операцию обычно делают следующим образом.
Однако мы можем применять операторы &&
и ||
только в том случае, если 0
, false
и пустая строка не являются допустимыми значениями.
В обозримом будущем операторы ?.
, ??
должны появиться и в JavaScript (в настоящее время они прошли стадию Stage0), подробнее об этих операторах в JavaScript можно прочитать в статье.
this
Как в C#, так и в JavaScript имеется ключевое слово this
. Обычно в C# понимание предназначения this
не вызывает никакого труда, однако в JavaScript это является одной из самых сложных концепций языка. Далее рассмотрим применение this
на примерах.
В C# ключевое слово this
указывает на текущий экземпляр класса.
В данном примере в выражении Console.WriteLine(this.name)
, this
указывает на переменную employee
.
Так как this
- текущий экземпляр класса, то его нельзя использовать в методах не привязанных к определенному типу, например в статических методах.
В JavaScript значение this
называется контекстом вызова и будет определено в момент вызова функции. Если одну и ту же функцию запускать в контексте разных объектов, она будет получать разный this
:
К тому же, в JavaScript присутствует возможность явного указания значения this
с помощью функций: call
, bind
, apply
. Например, вышеприведенный пример можно переписать следующим образом:
Часто бывает необходимо присвоить несколько полей объекта локальным переменным. Например, как часто вы наблюдаете подобный код?
Для подобных целей можно использовать деструктуризацию. Данную возможность в разной степени поддерживают оба языка.
В C# 7.0 для поддержки деструктуризации появился новый вид функций, называемый деконструкторами. Для того чтобы объявить деконструктор нам необходимо определить метод с именем Deconstruct
, все параметры которого должны быть объявлены с модификатором out
:
Поддержка деструктуризации или (destructuring assignment) в JavaScript появилась в шестом стандарте EcmaScript. С её помощь. можно присвоить массив или объект сразу нескольким переменным, разбив его на части.
Стоит отметить, что деструктуризация в JavaScript имеет больше возможностей, чем в C#:
В данной статье мы обсудили лишь самые основные концепции языков C# и JavaScript. Но остались не затронуты ещё многие аспекты:
Каждая из этих тем является достаточно обширной и будет раскрыта в дальнейшем в отдельной статье.