JavaScript datatyper och datastrukturer

Alla programmeringsspråk har inbyggda datastrukturer, men dessa skiljer sig ofta mellan olika programmeringsspråk. Den här artikeln tar upp de inbyggda datastrukturer som finns i JavaScript och dess egenskaper. Dessa kan användas för att bygga andra datastrukturer. Där möjligt kommer jömförelser med andra programmeringssråk göras.

Dynamisk typning

JavaScript är ett löst typat eller dynamiskt språk. I JavaScript är variabler inte bundna till att innehålla värden av någon särskild typ, alla variabler kan defineras och tilldelas värden av godtycklig typ:

let foo = 42;    // foo innehåller ett nummer
foo     = 'bar'; // foo innehåller en sträng
foo     = true;  // foo innehåller ett sanningsvärde/booleskt värde

Datatyper

Senaste ECMAScript standarden beskriver åtta inbyggda datatyper:

  • Sju primitiva datatyper:
  • och en sammansatt datatyp:
    • Objekt: Object
    • som i sin tur har ett flertal härledda typer.

Primitiva värden

Alla typer förutom förutom sammansatta/objekt är oföränderliga värden.Till exempel är strängar i JavaScript oföränderliga, till skillnad från språk som C. De här datatyperna kallas sammanfattande som primitiva typer.

Sanningsvärden / Booleska typen (Boolean)

Booleska värden representerar logiska sanningsvärden antingen: sann (true) eller falsk (false). Se Boolean och Boolean för fler detaljer.

Nolltypen (Null)

Nolltypen har ett enda värde: noll (null). Se null och Null för fler detaljer.

Odefinerade typen (Undefined)

En deklarerad variabel som inte har tilldelats ett värde kommer innehålla värdet odefinerad (undefined). Se undefined och Undefined för fler detaljer.

Nummertypen (Number)

ECMAScript har två inbyggda numeriska typer: Nummer (Number) och stora heltal (BigInt) (se nedan).

Nummertypen är binära flyttalsvärden enligt 64-bitars dubbelprecisionsformatet IEEE 754 (tal mellan -(253 -1) och 253 -1). Förutom att representera flyttal kan nummertypen också representera tre symboliska värden: Positiv oändlighet (+Infinity), negativ oändlighet (-Infinity), och icke-nummer NaN (eng. Not-a-Number).

Test för största tillgängliga värde eller minsta tillgängliga värde mellan positiv och negativ oändlighet +/-Infinity, kan använda konstanterna Number.MAX_VALUE och Number.MIN_VALUE respektive. Sedan ECMAScript 2015 är det möjligt att testa om tal ligger inom intervallet där dubbelprecisionsflyttal kan exakt representera heltal genom funktionen Number.isSafeInteger() eller jämförelse med konstanterna Number.MAX_SAFE_INTEGER och Number.MIN_SAFE_INTEGER. Utanför det här intervallet kan dubbelprecisionsflyttal inte representera alla heltal med unika representationer per heltal, utan kommer att använda en representation där fler än ett helttal kommer ge exakt samma binära representation och därmed inte kan skiljas åt.

Nummertypen har bara ett heltal som har fler än en representation: talet noll 0 representeras som antingen -0 eller +0. ("0" är en underförstådd +0). I nästan all kod kommer detta inte vara av någon som helst betydelse. Till exempel är jämförelsen +0 === -0  sann (true). Skillnaden mellan positive och negativ nolla kan dock observeras vid division med positiv eller negativ nolla:

> 42 / +0
Infinity
> 42 / -0
-Infinity

Även om de flesta tal bara representerar ett värde kan JavaScript utföra flera binära operationer. Dessa kan användas för att representera flera sanningsvärden i ett enda tal genom bitmaskning. Det anses dock vara dålig sed eftersom JavaScript har andra sätt att representera uppsättningar av sanningsvärden, som rader (Array) av sanningsvärden (Boolean) eller sanningsvärden tilldelade till namngivna egenskaper på objekt. Bitmaskning tenderar att göra kod svårare att läsa, förstå och underhålla. Det kan vara nödvändigt att använda sådana tekniker i begränsade miljöer, som vid lagringsstorleksbegränsningar eller då kraftiga begränsningar i datamängd änd över nätverket gäller. Tekniken bör ses som en sista åtgärd vid utrymmesoptimering.

Stora heltal (BigInt)

Stora heltalstypen (BigInt) är en numerisk primitiv i JavaScript som kan representera heltal med godtycklig precision. Stora heltal (BigInt) tillåter exakt lagring av helttal större än de som exakt kan representeras i nummer (Number). Ett stort heltal(BigInt) skapas genom att lägga till ett n efter en nummerliteral eller genom att anropa stora heltal-konstruktören (new BigInt).

Största värdet som exakt kan representeras med nummer (Number) lagras i konstanten  Number.MAX_SAFE_INTEGER. I och med stora heltal (BigInt) blir det möjligt att göra exakta beräkningar med större heltal än Number.MAX_SAFE_INTEGER. Detta kan observeras genom att öka tt stort heltal från Number.MAX_SAFE_INTEGER och se det förväntade resultatet:

> const x = 2n ** 53n;
9007199254740992n
> const y = x + 1n; 
9007199254740993n

Operatorerna +, *, -, ** och % kan användas med stora heltal (BigInt) precis som med nummer (Number). Ett stort heltal (BigInt) jämförs som löst lika med (==) med inte strikt lika med (===) motsvarande nummer (Number).

Ett stort heltal (BigInt) konverteras till sanningsvärden enligt samma beteendet som nummer (Number)  då tal omvandlas till sanningsvärden (Boolean): if, ||, &&, Boolean, !.

Stora heltal (BigInt) ger ett typfel (TypeError) om blandat  med nummer (Number) i numeriska operationer.

Strängtypen (String)

Strängtypen String används för data i textform i JavaScript. En sträng är en sekvens av element i form av 16-bitar kodenheter enligt UCS-2, i grunden icke teckenbärande 16-bitars heltal. Varje kodenhet upptar en position i strängen. Första kodenheten ligger på plats 0, andra på plats 1, sista på strängens längd minus ett. Strängens längd är antalet kodenheter.

Till skillnad från språk som C är strängar i JavaScript oföränderliga. Det går inte att förändra sekvensen av kodenheter i strängen efter att den skapades, däremot går det att skapa en ny sträng baserad på originalsträngen. Till exempel:

  • En delsträng av originalsträngen genom att välja en enstaka kodenhet (strängvariabel[elementindex]) eller använda en strängmetod som  String.substr().
  • En sammanlänkning av två strängar genom att använda sammanlänkningsoperatorn  (+) eller strängmetoden String.concat().

Akta för "sträng-typning" av er kod!

Det kan ibland bli frestande tt använda strängar för att representera komplex data. Detta kan ses ge några kortsiktiga fördelar:

  • Lätt att bygga complexa strängar genom sammanlänkning.
  • Strängar är lätta att avlusa (det som skrivs ut är alltid innehållet i strängen).
  • Strängar är den gemensamma nämnaren mellan många APIer (inmatningsfält, värden från lokal lagring, svar från XMLHttpRequest genom responseText, o.s.v.) så det kan bli frestande att hålla sig inom strängtypen.

Med konventioner kan alla datastrukturer bli strängar, men det betyder inte att det är en god idé. Man skulle till exempel med en separator efterlikna en lista, men en rad (Array) i JavaScript skulle vara mer lämplig. Om en separator dyker upp i en delsträng som används för att bygga listan skulle tyvärr listan bli felaktig, och ett utbrytningstecken skulle då bli nödvändigt, o.s.v. Detta skapar extra konventioner som måste följas och kodas för och blir en onödig börda vid underhåll av koden.

Använd strängar för data i form av text. Vid mer komplex data är det lämpligt att använda en tolk och lagra som lämplig abstraktion istället.

Symbol typen (Symbol)

Symboler är en ny datatyp i JavaScript introducerad i ECMAScript 2015. En symbol är et unikt och oföränderligt primitivt värde som kan användas som nyckel till en egenskap i ett objekt (se nedan). I vissa programmeringsspråk kallas symboler atomer. För fler detaljer se Symbol och Symbol-objektomslaget i JavaScript.

Objects

In computer science, an object is a value in memory which is possibly referenced by an identifier.

Properties

In JavaScript, objects can be seen as a collection of properties. With the object literal syntax, a limited set of properties are initialized; then properties can be added and removed. Property values can be values of any type, including other objects, which enables building complex data structures. Properties are identified using key values. A key value is either a String or a Symbol value.

There are two types of object properties which have certain attributes: The data property and the accessor property.

Data property

Associates a key with a value and has the following attributes:

Attributes of a data property
Attribute Type Description Default value
[[Value]] Any JavaScript type The value retrieved by a get access of the property. undefined
[[Writable]] Boolean If false, the property's [[Value]] can't be changed. false
[[Enumerable]] Boolean If true, the property will be enumerated in for...in loops. See also Enumerability and ownership of properties false
[[Configurable]] Boolean If false, the property can't be deleted, can't be changed to an accessor property and attributes other than [[Value]] and [[Writable]] can't be changed. false
Obsolete attributes (as of ECMAScript 3, renamed in ECMAScript 5)
Attribute Type Description
Read-only Boolean Reversed state of the ES5 [[Writable]] attribute.
DontEnum Boolean Reversed state of the ES5 [[Enumerable]] attribute.
DontDelete Boolean Reversed state of the ES5 [[Configurable]] attribute.

Accessor property

Associates a key with one or two accessor functions (get and set) to retrieve or store a value and has the following attributes:

Attributes of an accessor property
Attribute Type Description Default value
[[Get]] Function object or undefined The function is called with an empty argument list and retrieves the property value whenever a get access to the value is performed. See also get. undefined
[[Set]] Function object or undefined The function is called with an argument that contains the assigned value and is executed whenever a specified property is attempted to be changed. See also set. undefined
[[Enumerable]] Boolean If true, the property will be enumerated in for...in loops. false
[[Configurable]] Boolean If false, the property can't be deleted and can't be changed to a data property. false

Note: Attribute is usually used by JavaScript engine, so you can't directly access it (see more about Object.defineProperty()). That's why the attribute is put in double square brackets instead of single.

"Normal" objects, and functions

A JavaScript object is a mapping between keys and values. Keys are strings (or Symbols) and values can be anything. This makes objects a natural fit for hashmaps.

Functions are regular objects with the additional capability of being callable.

Dates

When representing dates, the best choice is to use the built-in Date utility in JavaScript.

Indexed collections: Arrays and typed Arrays

Arrays are regular objects for which there is a particular relationship between integer-key-ed properties and the 'length' property. Additionally, arrays inherit from Array.prototype which provides to them a handful of convenient methods to manipulate arrays. For example, indexOf (searching a value in the array) or push (adding an element to the array), etc. This makes Arrays a perfect candidate to represent lists or sets.

Typed Arrays are new to JavaScript with ECMAScript 2015 and present an array-like view of an underlying binary data buffer. The following table helps you to find the equivalent C data types:

TypedArray objects

Type Value Range Size in bytes Description Web IDL type Equivalent C type
Int8Array -128 to 127 1 8-bit two's complement signed integer byte int8_t
Uint8Array 0 to 255 1 8-bit unsigned integer octet uint8_t
Uint8ClampedArray 0 to 255 1 8-bit unsigned integer (clamped) octet uint8_t
Int16Array -32768 to 32767 2 16-bit two's complement signed integer short int16_t
Uint16Array 0 to 65535 2 16-bit unsigned integer unsigned short uint16_t
Int32Array -2147483648 to 2147483647 4 32-bit two's complement signed integer long int32_t
Uint32Array 0 to 4294967295 4 32-bit unsigned integer unsigned long uint32_t
Float32Array 1.2x10-38 to 3.4x1038 4 32-bit IEEE floating point number ( 7 significant digits e.g. 1.1234567) unrestricted float float
Float64Array 5.0x10-324 to 1.8x10308 8 64-bit IEEE floating point number (16 significant digits e.g. 1.123...15) unrestricted double double
BigInt64Array -263 to 263-1 8 64-bit two's complement signed integer bigint int64_t (signed long long)
BigUint64Array 0 to 264-1 8 64-bit unsigned integer bigint uint64_t (unsigned long long)

Keyed collections: Maps, Sets, WeakMaps, WeakSets

These data structures take object references as keys and are introduced in ECMAScript Edition 6. Set and WeakSet represent a set of objects, while Map and WeakMap associate a value to an object. The difference between Maps and WeakMaps is that in the former, object keys can be enumerated over. This allows garbage collection optimizations in the latter case.

One could implement Maps and Sets in pure ECMAScript 5. However, since objects cannot be compared (in the sense of "less than" for instance), look-up performance would necessarily be linear. Native implementations of them (including WeakMaps) can have look-up performance that is approximately logarithmic to constant time.

Usually, to bind data to a DOM node, one could set properties directly on the object or use data-* attributes. This has the downside that the data is available to any script running in the same context. Maps and WeakMaps make it easy to privately bind data to an object.

Structured data: JSON

JSON (JavaScript Object Notation) is a lightweight data-interchange format, derived from JavaScript but used by many programming languages. JSON builds universal data structures. See JSON and JSON for more details.

More objects in the standard library

JavaScript has a standard library of built-in objects. Please have a look at the reference to find out about more objects.

Determining types using the typeof operator

The typeof operator can help you to find the type of your variable. Please read the reference page for more details and edge cases.

Specifications

Specification Status Comment
ECMAScript 1st Edition (ECMA-262) Standard Initial definition.
ECMAScript 5.1 (ECMA-262)
The definition of 'Types' in that specification.
Standard
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'ECMAScript Data Types and Values' in that specification.
Standard Added Symbol.
ECMAScript Latest Draft (ECMA-262)
The definition of 'ECMAScript Data Types and Values' in that specification.
Draft

See also