Types
Numbers
Strings
Booleans
null and undefined
Objects
Immutable / Mutable Types
Type Conversions
Values
Variables
Variable Declaration
Variable Scope
are the kinds of values that can be represented and manipulated in a programming language
JavaScript types can be categorized as follows :
any value that does not belong to the primitive type
Numbers
JavaScript has a single number type,
there is no distinction between integer values and floating-point values
all numbers are represented in a 64-bit floating-point format
when a number appears directly in a JavaScript program,
it’s called a numeric literal
Numbers - rounding errors
only a finite number of
real numbers can be represented with
the binary floating point format,
which means that when working with them this will often be only an approximation
! This affects any programming language that uses binary floating-point
numbers
However, the values often are very close to the
correct value,
adequate for almost any purpose.
The problem arises
when attempting to compare values for equality.
! To perform critical financial calculations scaled integers should be used
Number literals
Number literals
Integer literals
! Since some implementations support octal literals and some do not, never write an integer literal with a leading zero. You can't know in this case whether an implementation will interpret it as an octal or decimal value.
Floating-point literals
the exponential
notation
represents the real number multiplied by 10 to the power of the exponent
Arithmetic operations
work with numbers is done using basic arithmetic
operators
Math.pow(2,53) Math.round(.6) Math.ceil(.6) Math.floor(.6)
Math.abs(-5) Math.max(x,y,z) Math.min(x,y,z) Math.random()
Math.PI Math.E Math.sqrt(3) Math.pow(3, 1/3)
Math.sin(0) Math.log(10) Math.exp(3) Math.log(100)/Math.LN10 Math.log(512)/Math.LN2
! NaN does not compare equal to any
other value, including itself.
This means that you can’t write x == NaN to determine
whether the value of a variable x is NaN.
Instead, you should use:
The related function isFinite() returns true if its argument is a number other than NaN, Infinity, or -Infinity.
The negative zero value (-0) is also somewhat unusual. It compares equal to positive zero, which means that the two values are almost indistinguishable, except when used as a divisor.
in JavaScript there are no errors
in cases of overflow, underflow, or division by zero
Overflow
Underflow
Division by zero
is not an error, it simply returns
infinity or negative infinity
! There is one exception,
however: zero divided by zero does not have a well-defined
value,
and the result of this operation is the special not-a-number
value (NaN)
NaN also arises if you attempt to:
Infinity // A read/write variable initialized to Infinity.
Number.POSITIVE_INFINITY // Same value, read-only.
1/0 // This is also the same value.
Number.MAX_VALUE + 1 // This also evaluates to Infinity.
Number.NEGATIVE_INFINITY // These expressions are negative infinity.
-Infinity
-1/0
-Number.MAX_VALUE - 1
NaN // A read/write variable initialized to NaN.
Number.NaN // A read-only property holding the same value.
0/0 // Evaluates to NaN.
Number.MIN_VALUE/2 // Underflow: evaluates to 0
-Number.MIN_VALUE/2 // Negative zero
-1/Infinity // Also negative 0
-0
are JavaScript’s type for representing text
a string is an immutable ordered sequence of 16-bit values, each of which typically represents a Unicode character (UTF-16 encoding )
the length of a string is the number of 16-bit values it contains
zero-based indexing is used: the first 16-bit value
is at position 0,
the second at position 1 and so on
the empty string is the string of length 0
there is no special type that represents a single element of a string,
simply use a string that has a length of 1
to include a string literally simply enclose the
characters of the string
within a matched pair of single or double
quotes (' or ")
the backslash character (\) combined with the character that follows
represents a character
that is otherwise not represented in the string
(the backslash allows to escape from the usual interpretation) :
if the \ character precedes any character other than the ones mentioned above, the backslash is simply ignored
concatenation, using the + operator
joins 2 strings, appending the second to the first
the length property - the number of 16-bit values it contains
methods that can be invoked on strings:
! as strings are immutable, methods like replace() and toUpperCase() return new strings, they do not modify the string on which they are invoked
...
scriem aici sau la objects? RegExp Class
there are only two values possible for this type
true or false
! reserved words
are usually the result of comparisons, commonly used in control structures
any value can be converted to boolean value:
toString() method can be applied to booleans to
convert them
to the strings “true” or ”false”
! there are no other useful methods for booleans
3 important boolean operators :
&& (AND)
operator
evaluates to a truthy value if and only if both of its
operands are truthy,
it evaluates to a falsy value otherwise
| |
(OR) operator
evaluates to a truthy value if either one (or
both) of its operands is truthy
and evaluates to a falsy value if both operands are falsy
! (NOT) operator
evaluates to true if its operand is falsy and evaluates to false if its operand is truthy
is a language keyword that
evaluates to a special value
that is usually used to indicate the absence of a value
it is typically regarded as the sole member of its own type
it can be used to indicate “no value” for numbers and strings as well as objects
is a predefined global variable
which also indicates the absence of value, a deeper kind of absence
it is the value:
despite the differences, both indicate absence of
values
and can be used interchangeably as both are falsy values and
behave
like false when boolean value is required
none have got any properties or methods
using . or [] to access a property or method of these values causes a TypeError
undefined = system-level, unexpected or error-like absence of value
null = program-level, expected or normal absence of value
any value that does not belong to the primitive type
(a number, a string, a boolean, null or undefined) is an object
An ordinary object (that is, a member of the type
object)
is a collection of properties, where each property has a name (usually a string, including the empty string) and a value (either a primitive value or an object, never undefined)
! no object may have two properties with the same name
an object can also inherit the properties of another object
known as its prototype
the methods of an object are typically inherited properties, and this “prototypal inheritance” is a key feature of JavaScript
the most common things to do with objects are
create them and set, query, delete, test and enumerate their properties
Special kind of objects:
Function = an object that has executable code associated with it
it may be invoked to run that executable code and return a computed value
JavaScript defines a special language syntax for working with them
The Global Object
= a regular object
that serves a very important purpose:
its properties are the globally defined symbols that are available to a JavaScript program
When the JavaScript interpreter starts (or whenever a web browser loads a new page), it creates a new global object and gives it an initial set of properties that define:
besides all
predefined global values,
the global object also holds program-defined globals
(when a a global variable is declared, that variable is a property of the global object)
Strings, numbers and booleans
are not objects, so why do they have properties? Whenever you
try to refer to a property, JavaScript converts the
string value to an object as if by calling new String(), new
Number(), new Boolean()
This object inherits string/number/boolean
methods and is used to resolve the property reference. Once the
property has been resolved, the newly created object is discarded.
Wrapper Objects = the temporary objects
created when you access
a property of a string, number, or boolean
! there are no wrapper objects for the null and undefined values: any attempt to access a property of one of these values causes a TypeError
it is possible to explicitly create wrapper objects,
by invoking the String(), Number(), or
Boolean() constructors:
JavaScript converts wrapper objects into the wrapped primitive value as necessary
the objects usually, but not always, behave just like the values
the == equality operator treats
a value and its wrapper object as equal,
the === strict equality operator distinguishes them
the typeof operator will also show you the difference between
a primitive value and its wrapper objects
Types
primitives - numbers, strings, booleans, null, undefined
their value can't be changed ("mutated")
this is obvious for numbers and booleans
(it doesn’t even make sense to change the value of a number/boolean)
but it is not so obvious for strings
since strings
are like arrays of characters,
you might expect to be able to alter the character at any specified index
in fact, JavaScript does not
allow this,
and all string methods that appear to return a modified string are, in fact, returning a new string value
primitive values are also compared by value
objects
their values can be changed
and
they are not compared by value
two objects are not equal even if
they have the same properties and values
2 arrays are not equal even if
they have the same elements in the same order
comparison by reference
two object values are the
same if and only if
they refer to the same underlying object
assigning an object or array to a variable simply assigns
the
reference: it does not create a new copy of the object
if you want
to make a new copy of an object or array,
you must explicitly copy
the properties of the object or
the elements of the array
in
order to compare two distinct objects or arrays
their properties or elements must be compared
JavaScript is very flexible about the types of
values it requires
when JavaScript expects a certain kind of value,
no matter the value supplied, it will try to convert it as needed
Value |
Converted to |
|||
String |
Number |
Boolean |
Object |
|
undefined |
“undefined” |
NaN |
false |
throws TypeError |
null |
“null” |
0 |
false |
throws TypeError |
true |
“true” |
1 |
|
new Boolean(true) |
false |
“false” |
0 |
|
new Boolean(false) |
“” (empty string) |
|
0 |
false |
new String(“”) |
“1.2” (nonempty,numeric) |
|
1.2 |
true |
new String(“1.2”) |
“one” (nonempty, non-numeric) |
|
NaN |
true |
new String(“one”) |
Value |
Converted to |
|||
String |
Number |
Boolean |
Object |
|
0 |
"0" |
|
false |
new Number(0) |
-0 |
"0" |
|
false |
new Number(-0) |
NaN |
“NaN” |
|
false |
new Number(NaN) |
Infinity |
“Infinity” |
|
true |
new Number(Infinity) |
-Infinity |
“-Infinity” |
|
true |
new Number(-Infinity) |
1 (finite, non-zero) |
"1" |
|
true |
new Number(1) |
{} (any object) |
* |
** |
true |
|
[] (empty array) |
"" |
0 |
true |
|
[9] (1 numeric elt) |
"9" |
9 |
true |
|
['a'] (any other array) |
use join() method |
NaN |
true |
|
function(){} (anu function) |
* |
NaN |
true |
|
but
object-to-string and object-to-number conversions are more complicated
these are performed by invoking a method of the object to be converted
objects inherit two different methods that perform conversions :
toString() - returns a string representation of the object
and
valueOf() - is supposed to convert an object to a primitive value that represents the
object, if any such primitive value exists
({x:1, y:2}).toString() // => "[object Object]"
[1,2,3].toString() // => "1,2,3"
(function(x) { f(x); }).toString() // => "function(x) {\n f(x);\n}"
/\d+/g.toString() // => "/\\d+/g"
new Date(2010,0,1).toString() // => "Fri Jan 01 2010 00:00:00 GMT-0800 (PST)"
valueOf() method
a less well-defined conversion function
objects are compound values, and most objects cannot really be represented by a single primitive value, so by default the method simply returns the object itself rather than returning a primitive
primitives - wrapper classes define valueOf() methods that return the wrapped primitive value
arrays, functions and regular expressions simply inherit the default method which returns the object itself
Date class - defines a valueOf() method that returns the date in its internal representation, the number of milliseconds since January 1, 1970
* convert object to string
1. object has a toString() method => JavaScript calls it
returned value is a primitive? => it is converted to a string (if not already a string) and returned
2. object has no toString() method or the method does not return a primitive
=> JavaScript looks for valueOf() and calls it if method exists
returned value is a primitive? => it is converted to a string (if not already a string) and returned
3. TypeError is thrown, if no primitive value can be obtained from either toString() or valueOf()
** convert object to number
1. object has a valueOf() method => JavaScript calls it
returned value is a primitive? => it is converted to a number (if necessary) and returned
2. object has no valueOf() method or the method does not return a primitive
=> JavaScript looks for toString() and calls it if method exists
returned value is a primitive? => it is converted to a number (if not already a number) and returned
3. TypeError is thrown, if no primitive value can be obtained from either valueOf() or
toString()
for
+ / == / != / relational operators (<,>,<=,>=)
if either of the operands is an object, it is converted using a special object-to-primitive conversion rather than the object-to-number conversion used by the other arithmetic operators
for
+ / == /!=
the conversion includes a special case for Date objectsthe object-to-primitive conversion is basically an object-to-number conversion (valueof() first) for all objects that are not dates, and an object-to-string conversion (toString() first) for Date objects
the primitive value returned by valueOf() or toString() is used directly without being forced to a number or string
Conversions and equality
because JavaScript can convert values flexibly,
its == equality operator is also flexible with its notion of equality
0
null == undefined // these values are treated as equal
"0" == 0 // string is converted to a number before comparing
0 == false // boolean is converted to number before comparing
"0" == false // both operands convert to number before comparing
but undefined == false // not true, as == operator never attempts to
// convert its operands to booleans
Explicit conversions
although many type conversions are performed automatically,
sometimes explicit conversions are needed
invoking the functions Number(), String(), Boolean() and Object()
without the new operator
Number("3") // => 3
String(false) // => "false" or use false.toString()
Boolean([]) // => true
Object(3) // => new Number(3)
Object() // => creates an empty object
attempting to convert null or undefined to an object => TypeError
x + "" // + converts the second operator to string if one operator is a string
+x // unary + operator converts its operand to number
!!x // unary ! operator converts its operand to a boolean and negates it
var n = 17;
binary_string = n.toString(2) // evaluates to "10001"
octal_string = "0" + n.toString(8) // evaluates to "021"
hex_string = "0x" + n.toString(16) // evaluates to "0x11"
number-to-string
when working with financial or scientific data, needing to have control
over the number of decimal places,
or the number of significant digits in the output,
or whether exponential notation is used
convert number to strings using three methods defined by the Number class:
toFixed() - converts a number to a string with a specified number of digits after the decimal point
toExponential() - converts a number to a string using exponential notation, with one digit before the
decimal point and a specified number of digits after the decimal point
toPrecision() - converts a number to a string with the number of significant digits you specify
var n = 123456.789;
n.toFixed(0); // "123457"
n.toFixed(2); // "123456.79"
n.toFixed(5); // "123456.78900"
n.toExponential(1); // "1.2e+5"
n.toExponential(3); // "1.235e+5"
n.toPrecision(4); // "1.235e+5"
n.toPrecision(7); // "123456.8"
n.toPrecision(10); // "123456.7890"
string-to-number
Number()
attempts to parse the string as an integer or floating point, only works for base-10 integers and does not allow trailing characters that are not part of the literal
there are two global functions (not methods of any class) which are more flexible:
parseInt() - parses only integers, if string begins with "0x"/"0X" interprets number as hexadecimal
parseFloat() - parses integers and floating-point functions
both functions skip leading whitespace, parse as many numeric characters as they can, and ignore anything that follows
if the first nonspace character is not part of a valid numeric literal, they return NaN
parseInt("3 pieces") // => 3
parseInt("-12.34") // => -12
parseInt("0xff") // => 255
parseInt("0XFF") // => 255
parseInt("-0XFF") // => -255
parseInt("0.1") // => 0
parseInt(".1") // => NaN: integers can't start with "."
// optional second argument specifies the base of the number to be parsed, values 2-36
parseInt("11",2) // => 3 ( 1*2 + 1 )
parseInt("ff",16) // => 255 ( 15*16 + 15 )
parseInt("zz",36) // => 1295 ( 35*36 + 35 )
parseInt("077",8) // => 63 ( 7*8 + 7)
parseFloat("3.14 meters") // => 3.14
parseFloat(".1") // => 0.1
parseFloat("$72.47") // => NaN: numbers can't start with "$"
computer programs work by manipulating values
in computer science, a value is an expression which cannot be evaluated any further (a normal form)
the members of a type are the values of that type
in JavaScript values are converted liberally from one type to another, which affects definition of equality (== vs ===)
when a program needs to retain a value for future use, it assigns the value to (or “stores” the value in) a variable
A variable defines a symbolic name for a value
and allows the value to be referred to by name
var message = "I'm a variable";
the same var keyword can be used to declare multiple variables var i, j = 0, k;
repeated declarations are legal and harmless
omitted declarations
in non-strict mode, assigning a value to an undeclared variable actually creates that
variable as a property of the global object which works much like, but not exactly the same as, a properly declared global variable
but
! it's a bad habit, source of many bugs
initialization
if an initial value is not
specified with the var statement,
the variable is undefined until the code stores a value in it
variables are untyped
you can assign a value of any type to a variable, and you can later assign a value of a different type to the same variable
the scope of a variable is
the
region of your program source code in which it is defined
Lexical scoping
variables declared outside a function are global variables,
have global scope
and
are visible (defined) throughout the program
variables declared inside a function are local
variables,
have function scope
and
are visible only to code that appears inside that function
(including within any functions that are nested within that function)
function parameters also count as local variables and are defined only within the body of the function
within the body of a function, a local variable
takes precedence over a global variable with the same name
local variables must always be declare with var,
otherwise the global variable is used
function definitions can be nested,
each function has its own local scope
hoisting
all variables declared within a function are visible
throughout the body of the function
=> they are visible even before they are declared
JavaScript code behaves as if all variable declarations in a function
(but not any associated assignments) are “hoisted” to the top of the function (as opposed to "block scope")
var scope1 = "global1", // declared three global variable
scope2 = "global2",
scope3 = "global3";
function checkscope() {
console.log(scope1); // prints undefined, not "global1" -> hoisting
var scope1 = "local1"; // declared a local variable with the same name
scope2 = "local2"; // changed the value of the global variable
var myscope = "myLocal" // declared a local variable
return [scope1, scope2, myscope]; // returned three values
}
checkscope(); // ["local1", "local2", "myLocal"]
scope1; // "global"
scope2; // "local2", global variable has changed
when declaring a global variable, it actually means defining
a property of the global object
if the var keyword is used, the property that is created is nonconfigurable, which means that it cannot be deleted
with the delete operator
otherwise
undeclared variables are regular, configurable properties of
the global object and they can be deleted
local variables can be thought of as the properties of an object associated with each function invocation ("call object")
JavaScript allows to refer to the global object with the this keyword,
but it does not give any way to refer to the object in which local variables are stored
every chunk of JavaScript code (global code or function)
has a scope chain associated with it
the Scope Chain
is a list or chain of objects that defines the variables that are “in scope” for that code