
Mi camino más o menos serio en la programación comenzó con la escritura de programas en C #, a veces intenté escribir en JavaScript, y de vez en cuando caí en un estupor en situaciones en las que ingresé incorrectamente el nombre de la variable y me enteré más tarde. muchos muchos años una hora de depuración, ya que no estaba cerca de mi compilador, lo que me ayudaría en tiempos difíciles. Después de un tiempo, además de C #, comencé a escribir mucho código JavaScript y ahora puedo hacerlo sin mucha dificultad, ya no estoy confundido por la conversión implícita de tipos y la escritura dinámica.
En este artículo, me gustaría sistematizar mi conocimiento básico de estos idiomas y considerar sus similitudes y diferencias. Este artículo puede servir como guía para los desarrolladores de C # que desean aprender JavaScript y viceversa. También quiero señalar que este artículo describe las capacidades de JS del lado del cliente, ya que no tengo experiencia en desarrollo en Node.js. Entonces, si aún no ha perdido interés, comencemos.
Espacio de nombres y módulos js
En cada programa, para evitar conflictos en los nombres de variables, funciones, clases u otros objetos, los combinamos en algunas áreas. Por lo tanto, si dos áreas diferentes contienen elementos con el mismo nombre, no ocurrirá ningún conflicto.
En C #, los espacios de nombres se utilizan para dividir un programa en partes. El namespace
palabras clave namespace
utiliza para declararlos. Por ejemplo, si queremos crear un conjunto de componentes de interfaz de usuario, es lógico ponerlos todos en un espacio de nombres, por ejemplo, Components
. Es habitual que el espacio de nombres tenga los siguientes nombres [AssemblyName].[DirectoryName].[DirectoryName].[...]
Nombre de [AssemblyName].[DirectoryName].[DirectoryName].[...]
. En cada archivo, la clase del componente de interfaz de usuario debe colocarse dentro del espacio de nombres:
El contenido del archivo ComboBox.cs
:
namespace AssemblyName.Components { public class ComboBox {
Para comenzar a usar componentes, debe importarlos desde el espacio de nombres de la siguiente manera using AssemblyName.Components
. Con este método de conexión de una línea, importamos todos los objetos al archivo actual.
JS usa módulos ES para el mismo propósito. Cuando los usamos, en cierta medida emulamos el comportamiento de los espacios de nombres escribiendo código adicional. Considere el mismo ejemplo con una biblioteca de componentes. Digamos que tenemos la carpeta Components
, que contiene los componentes de la interfaz de usuario ComboBox.js
, Button.js
, Button.js
, etc. Para obtener un comportamiento similar en comparación con el espacio de nombres en la carpeta Components
, debe crear un archivo index.js
que contendrá el siguiente código:
export { default as Dialog } from './ComboBox'; export { default as Button } from './Button'; export { default as Checkbox } from './Checkbox';
Para utilizar estos componentes, debe importarlos al archivo actual. Esto se puede hacer de la siguiente manera: import * as Components from './../Components'
, después de la palabra clave from, debemos especificar la ruta a la carpeta en la que se encuentran todos los componentes descritos.
Formas de declarar variables
La palabra clave var
Como sabe, C # es un lenguaje de programación fuertemente tipado, por lo tanto, al declarar una variable, el compilador debe conocer su tipo, para esto generalmente se indica antes de su nombre.
double pi = 3.14; User user = new User(); int[] a = new[] { 0, 1, 2 };
Pero también podemos decirle al compilador que debe inferir el tipo por sí solo de la expresión que sigue al signo de asignación. Esto fue posible al introducir la palabra clave var
en C # 3.0.
Con var
podemos crear objetos de tipo anónimo:
En JavaScript, también puede usar la palabra clave var
para declarar variables, sin embargo, a diferencia de C #, el alcance de estas variables será la función completa o el objeto de window
si la variable se declaró fuera de la función.
var a = 5 // - window function go() { var a = 6 // - go // ... }
Aunque tiene la capacidad de declarar variables usando var
en JavaScript, esto no se recomienda ahora, después del lanzamiento del estándar ES6, se agregó la palabra clave let
, que también le permite declarar variables, pero su ventaja es que su alcance será el bloque en el que se declaran, no la función completa.
Constantes
Tanto C # como JavaScript usan la palabra clave const
para declarar un campo constante. Es cierto que vale la pena señalar que el concepto de una constante en este caso es diferente para estos idiomas.
En C #, una constante es una expresión que se puede evaluar completamente en la etapa de compilación, es decir, las constantes pueden ser números, booleanos, cadenas o referencias nulas.
const int c1 = 5; const int c2 = c1 + 100; const string c3 = ""; const bool c4 = true; const User human = null; const User human = new User(firstName);
En JavaScript, el valor de una constante tampoco se puede cambiar, sin embargo, no hay restricciones en el valor, ya que en C #, puede asignarle valores / objetos / matrices. Sin embargo, si un objeto se asigna a una constante, la constante en sí está protegida de los cambios, pero no las propiedades dentro de ella:
const c1 = 5; const c2 = c1 + 100; const c3 = ""; const c4 = true; const user = { name: "" }; user.name = "";
void
clave void
Mientras escribía este artículo, experimenté con funciones en la consola y, por costumbre, comencé a describir la función como en C # void SomeFunction...
y fue una gran sorpresa para mí cuando descubrí que la palabra clave JavaScript no es void
. Resultó que void
en JavaScript es un operador unario que calcula el valor de un operando, luego lo descarta y devuelve undefined
.
alert("!"); // "!" alert(void "!"); // undefined
Por lo tanto, podemos decir que el uso de void
indica claramente la ausencia de un valor de retorno; para obtener más detalles sobre ejemplos de su uso, consulte el siguiente artículo .
En C #, void
no void
un operador, pero esencialmente tiene un significado similar. Aquí, indica la ausencia de un valor de retorno de función:
public void SampleMethod() {
Sin embargo, como puede ver en el ejemplo anterior, void
en el lugar donde generalmente se indica el tipo del valor de retorno, y esto no es accidental, porque en C # void
también void
un tipo.
var t = typeof(void); t.Name
void
como tipo solo se puede usar en un contexto inseguro cuando se trabaja con punteros.
unsafe { void* identifier;
Palabra clave new
En JavaScript, la new
palabra clave es un operador, y se usa de la manera habitual para muchos lenguajes tipo C para crear un objeto.
function Animal() { //... } const animal = new Animal();
En C #, new
se puede usar para los siguientes propósitos:
- para crear objetos;
- para ocultar el miembro heredado de la clase base;
- para limitar los tipos que se pueden usar como argumentos para un parámetro de tipo en una clase genérica.
El primer caso es similar al uso de new
en JavaScript.
class Animal {
Tipos de datos básicos
Cada idioma tiene tipos de datos: primitivas en función de las cuales se construyen otros tipos de datos, echemos un vistazo a los tipos de datos que se nos proporcionan en C # y JavaScript.
Tipos primitivos de C #:
- Entero
sbyte
: sbyte
, short
, int
, long
- Entero sin signo:
byte
, ushort
, uint
, ulong
- Caracteres Unicode:
char
- Conjunto de caracteres Unicode:
char
- Números de coma flotante:
float
, double
- Decimal Precimal:
decimal
- Valor booleano:
bool
La clase base es Object
.
Para JS:
Tipos de datos primitivos:
- Numero
number
- Cadena
string
- Booleano
boolean
null
especial- Significado especial
undefined
symbol
El tipo base es Object
.
Después de estudiar las primitivas de ambos idiomas, podemos llegar a las siguientes conclusiones:
- En lugar de un conjunto suficientemente grande de tipos de números, JavaScript tiene un solo
number
tipo; - JavaScript no tiene un tipo
char
; en su lugar, use un tipo de string
; - En ambos idiomas, el tipo base es
Object
; - Una característica distintiva de JS es que
null
e undefined
se separan en tipos separados, mientras que en C # null
es una palabra clave que indica la ausencia de un valor. - JS tiene el tipo de
symbol
, que se usa principalmente dentro del estándar JavaScript mismo, para poder agregar nuevas funcionalidades sin conflicto con la base de código existente.
Como regla general, ahora hay más y más aplicaciones en las que es necesario procesar datos en el cliente, lo que requiere una mayor precisión en los cálculos. Actualmente, JavaScript carece de la capacidad incorporada para trabajar con grandes números, pero en un futuro próximo se planea agregar un nuevo tipo de BigInt
. Para resolver problemas similares en C # hay una clase System.Numerics.BigInteger
.
Verificación de tipo de objeto
La verificación de tipos es una operación bastante típica para la mayoría de los lenguajes de programación. Según el tipo, podemos realizar varias acciones. Por ejemplo, considere un ejemplo de vida: escucha un timbre, si un vecino borracho se le acercó (un objeto con el tipo de vecino borracho ) para pedir prestado dinero, entonces es poco probable que le abra la puerta, pero si su mejor amigo está detrás de la puerta (un objeto con el mejor tipo amigo ), entonces no dudes en dejarlo entrar al apartamento. C # y JavaScript también proporcionan facilidades para verificar el tipo de objetos.
typeof
operador
Para obtener información de tipo, tanto C # como JavaScript tienen el operador typeof
. Veamos cómo funciona en ambos idiomas:
En C #, el operador typeof
se aplica a un tipo y devuelve un objeto de la clase Type
que contiene toda la información del tipo.
namespace Zoo { public class Animal {} } Type t = typeof(Animal); t.Name
En JS, typeof
devuelve una cadena que indica el tipo de operando.
typeof 30 // 'number' typeof Symbol() // 'symbol' typeof undefined // 'undefined' // typeof new Animal() // object typeof null // 'object' typeof [1,2,3] // 'object' // typeof function() {} // 'function'; typeof class C {} // 'function';
En el ejemplo anterior, puede observar algunas características de este operador. Parece lógico que la expresión typeof new Animal()
devuelva la cadena 'Animal'
y typeof [1,2,3]
- la cadena Array
, aunque paradójicamente, el resultado en ambos casos es 'object'
. Además, debido al hecho de que las clases en JS son un envoltorio sobre las funciones, el tipo de expresión de la typeof class C {}
devolverá 'function'
lugar de 'class'
. Otro hecho interesante es que el tipo de expresión typeof null
devolverá 'object'
. En JavaScript, este operador tiene un gran inconveniente: todos los objetos no primitivos tienen el mismo aspecto, todos tienen el mismo tipo de object
.
Vale la pena señalar que en JavaScript typeof
se puede aplicar a cualquier cosa: objetos, funciones, clases, etc. ... En C #, este operador se aplica solo a los tipos.
Además de obtener información sobre un tipo, a veces puede ser útil verificar que un objeto pertenece a un tipo en particular.
En C # hay un operador is
para estos fines.
class Person { }
En JavaScript, para saber a qué tipo pertenece un objeto, debe usar el operador - instanceof
.
function Person() {} function Programmer() {} // Programmer Person Programmer.prototype = Object.create(Person.prototype); var person = new Person(); var programmer = new Programmer(); console.log(person instanceof Person); // true console.log(person instanceof Programmer); // false console.log(programmer instanceof Person); // true console.log(programmer instanceof Programmer); // true
Cheque booleano y nulo
Casi en todas partes, para no obtener una Null reference exception
, antes de usar una variable, la verificamos para que sea null
y, en el caso de JavaScript, también para undefined
.
En C #, vemos constantemente un código similar:
if(user != null && String.IsNullOrEmpty(user.name)) { user.SetName(""); }
En JavaScript, esta construcción se puede escribir algo más corta. Esto se debe al hecho de que, a diferencia de C #, en JavaScript, muchos valores, excepto false
cuando se convierte también se consideran false
:
null
undefined
- "" (Línea vacía)
0
NaN
(no es un número)
Por lo tanto, el código C # anterior se puede escribir de la siguiente manera:
if (user && !user.name) { user.setName(""); }
o
user && !user.name && user.setName("");
Debido al hecho de que null
comprobaciones null
son ubicuas, el Operador de propagación nula se agregó en C # 6.0 .?
.
Código C #:
if (user != null && user.parent != null && user.parent.parent != null) { user.parent.parent.SetName(""); }
Con su ayuda, esta sección de código se puede reescribir de la siguiente manera:
user?.parent?.parent?.SetName("");
En JavaScript, generalmente se hace de la siguiente manera:
user && user.parent && user.parent.parent && user.parent.parent.setName("");
Establecer valores predeterminados
Otra operación común es establecer valores predeterminados, a partir de la versión 2.0 en C # Null Coalescing Operator apareció - ??
.
Las siguientes dos líneas de código C # son equivalentes:
var name = user != null && user.name != null ? user.name : ""; var name = user?.name ?? "";
En JavaScript, una operación similar generalmente se realiza de la siguiente manera.
var name = user && user.name || "";
Sin embargo, podemos usar los operadores &&
y ||
solo si 0
, false
y la cadena vacía no son valores válidos.
En el futuro previsible, los operadores ?.
??
debería aparecer en JavaScript (ahora han pasado la etapa Stage0 ), se pueden encontrar más detalles sobre estos operadores en JavaScript en el artículo .
Esta palabra clave
Tanto C # como JavaScript tienen this
. Por lo general, en C #, el propósito de this
es sencillo, pero en JavaScript este es uno de los conceptos de lenguaje más complicados. Además consideraremos la aplicación de this
en ejemplos.
En C #, la this
apunta a la instancia actual de la clase.
class User { public string Name { get; set; } public void PrintEmployee() { Console.WriteLine(this.name); } } var employee = new Employee(); E1.PrintEmployee();
En este ejemplo, en la expresión Console.WriteLine(this.name)
, this
apunta a la variable employee
.
Como this
es la instancia actual de la clase, no se puede usar en métodos que no estén vinculados a un tipo específico, por ejemplo, en métodos estáticos.
En JavaScript, this
se llama el contexto de la llamada y se determinará cuando se llame a la función. Si ejecuta la misma función en el contexto de diferentes objetos, recibirá un mensaje diferente:
var user = { firstName: "" }; var admin = { firstName: "" }; function func() { alert( this.firstName ); } user.f = func; admin.g = func; // this : user.f();
Además, en JavaScript existe la posibilidad de indicar explícitamente el valor de this
mediante funciones: call
, bind
, apply
. Por ejemplo, el ejemplo anterior se puede reescribir de la siguiente manera:
var user = { firstName: "" }; var admin = { firstName: "" }; function func() { alert( this.firstName ); } // this : func.call(user); // func.call(admin); // func.bind(user)();// func.bind(admin)();//
Reestructuración
A menudo es necesario asignar varios campos de un objeto a variables locales. Por ejemplo, ¿con qué frecuencia observa un código similar?
void Method(User user) { var firstName = user.FirstName; var lastName = user.LastName;
Para tales fines, puede utilizar la desestructuración. Ambos idiomas admiten esta función en diversos grados.
C # 7.0 introdujo un nuevo tipo de función llamada deconstructores para soportar la desestructuración. Para declarar un deconstructor, necesitamos definir un método llamado Deconstruct
, cuyos parámetros deben declararse con el modificador out
:
class Person { public string FirstName { get; set; } public string LastName { get; set; }
El soporte para la desestructuración o (asignación de desestructuración) en JavaScript apareció en el sexto estándar EcmaScript. Con su ayuda Puede asignar una matriz o un objeto a varias variables a la vez, dividiéndolo en partes.
let [firstName, lastName] = ["", ""]; let [firstName, _ ] = ["", ""]; let { firstName, lastName } = { firstName: "", lastName: "" }; let { firstName } = { firstName: "", lastName: "" };
Vale la pena señalar que la reestructuración en JavaScript tiene más características que en C #:
- Cambiar el orden de las variables;
- No es necesario declarar explícitamente deconstructores;
- Soporte de desestructuración de matriz;
- Establecer valores predeterminados;
- Asignación de propiedades de un objeto a una variable con un nombre diferente;
- Soporte para la desestructuración anidada.
Conclusión
En este artículo, hemos discutido solo los conceptos más básicos de los lenguajes C # y JavaScript. Pero muchos aspectos no se vieron afectados:
- colecciones
- las funciones
- clases
- multihilo
Cada uno de estos temas es bastante extenso y se revelará más adelante en un artículo separado.