an expression is a phrase
that an interpreter
can evaluate to produce a value
complex expressions
are built from simpler expressions
using operators
3 + 4
a * b
c = 7
an operator combines the values of its operands
&
evaluates to a new value
primary expressions
are constant or literal values
language keywords & variable references
15.67 //=> number literal
'JavaScript' //=> string literal
/[a-zA-Z0-9]/ //=> regular expression literal
null //=> evaluates to `null` value
false //=> evaluates to boolean `false` value
this //=> evaluates to `current` object
undefined //=> evaluates to global variable `undefined`
title //=> evaluates to the value of `title` variable
object & array initializers
are expressions whose values
are a newly created object or array
array initializer
are a comma-separated list of expressions
placed between square brackets
[14 + 1, 10 + 5, 30 / 2] //=> [15, 15, 15]
object initializer
are a comma-separated list of expressions
placed between curly brackets
where each expression is prefixed by a name
var obj = {
first: 14 + 1,
second: 10 + 5,
third: 30 / 2
};
console.log(obj); //=> Object {first: 15, second: 15, third: 15}
the expressions in an object or array initializer
are evaluated each time the initializer is evaluated
this means that the value of the expressions
may be different each time it is evaluated
a
function definition expression
defines a JavaScript function
&
the value is the newly created function
var multiply = function (a, b) {
return a * b;
};
property access expressions
evaluate to the value of an object property
or an array element
there are two syntaxes defined for property access
dot notation
expression.identifier
var obj = {
a: 15
};
obj.a //=> 15
where the expression specifies the object & the identifier specifies the name of the property to be accessed
&
bracket notation
expression[expression]
var obj = {
ab: 15
};
obj['a' + 'b'] //=> 15
obj['ab'] //=> 15
where the first expression is followed by another expression enclosed in square brackets whose value has to be the name of the desired property
the expression before the . or [ is first evaluated
if the value is null or undefined it throws a TypeError
dot notation syntax is the simpler of the two
BUT
it can only be used when the property that needs to be accessed
is a legal identifier
var obj = {
a: 15,
b: [7.5, 7.5],
c: {
d: {
e: 30 - 15
}
}
};
var arr = [ 1, 'JavaScript', obj, function () { return obj; } ];
obj.a //=> 15
obj.b[1] //=> 7.5
obj.c.d.e //=> 15
obj['c']['d'].e //=> 15
obj['a' + 'b'][0] //=> TypeError: Cannot read property '0' of undefined
arr[0] //=> 1
arr[2].a //=> 15
arr[2]['c']['d']['e'] //=> 15
arr[3]().c.d.e //=> 15
a more complex example
invocation expressions
are JavaScript's syntax for executing functions or methods
someFunction(15); // `someFunction` is the function expression & `15` is the argument expresion
var obj = {
age: null,
setAge: function (age) {
this.age = age;
},
getAge: function () {
return this.age;
}
};
obj.setAge(15); //=> obj.age value is now 15
obj.getAge(); //=> 15 - returns the obj.age value
when an invocation expression is evaluated
the function expression is evaluated first
&
then the argument expressions are evaluated
to produce a list of argument values
if the value of the function expression
is not a callable object it throws a TypeError
Object.push(obj, 'title', 'JavaScript - The Basics');
//=> TypeError: undefined is not a function
next if callable
argument values are assigned to parameter names
&
then the function body is executed
an
object creation expression
creates a new object & invokes a function to initialize the properties of that object
this function is called constructor
object creation expressions
are like invocation expressions
except they are prefixed by the new keyword
function Course(title) {
this.title = title || 'Untitled';
}
var course = new Course('JavaScript - The Basics');
console.log(course); //=> Course {title: "JavaScript - The Basics"}
operators
are used in
arithmetic / comparison / logical /
assignament / relational / evaluation / special
expressions
operators
are punctuation characters like + or =
or
keywords such as delete and typeof
Operator | Operation | Associativity | Number of operands | Types |
++ | pre- or post-increment | right-to-left | 1 | lval ⇒ num |
-- | pre- or post-decrement | right-to-left | 1 | lval ⇒ num |
- | negate number | right-to-left | 1 | num ⇒ num |
+ | convert to number | right-to-left | 1 | num ⇒ num |
~ | invert bits | right-to-left | 1 | int ⇒ int |
! | invert boolean value | right-to-left | 1 | bool ⇒ bool |
delete | remove a property | right-to-left | 1 | lval ⇒ bool |
typeof | determine type of operand | right-to-left | 1 | any ⇒ str |
void | return undefined value | right-to-left | 1 | any ⇒ undef |
*, /, % | multiply, divide, remainder | left-to-right | 2 | num, num ⇒ num |
+, - | add, subtract | left-to-right | 2 | num, num ⇒ num |
+ | concatenate strings | left-to-right | 2 | str, str ⇒ str |
<< | shift left | left-to-right | 2 | int, int ⇒ int |
the below table lists all JavaScript operators
ordered by their precedence
(first having heigher precedence)
horizontal blue lines separate operators with different precedence levels
Operator | Operation | Associativity | Number of operands | Types |
>> | shift right with sign extension | left-to-right | 2 | int, int ⇒ int |
>>> | shift right with zero extension | left-to-right | 2 | int, int ⇒ int |
<, <=, >, >= | compare in numeric order | left-to-right | 2 | num, num ⇒ bool |
<, <=, >, >= | compare in alphabetic order | left-to-right | 2 | str, str ⇒ bool |
instanceof | test object class | left-to-right | 2 | obj, func ⇒ bool |
in | test whether property exists | left-to-right | 2 | str, obj ⇒ bool |
== | test for equality | left-to-right | 2 | any, any ⇒ bool |
!= | test for inequality | left-to-right | 2 | any, any ⇒ bool |
=== | test for strict equality | left-to-right | 2 | any, any ⇒ bool |
!== | test for strict inequality | left-to-right | 2 | any, any ⇒ bool |
& | compute bitwise AND | left-to-right | 2 | int, int ⇒ int |
^ | compute bitwise XOR | left-to-right | 2 | int, int ⇒ int |
| | compute bitwise OR | left-to-right | 2 | int, int ⇒ int |
&& | compute logical AND | left-to-right | 2 | any, any ⇒ any |
|| | compute logical OR | left-to-right | 2 | any, any ⇒ any |
? : | choose scond or third operand | right-to-left | 3 | bool, any, any ⇒ any |
= | assign to a variable or property | right-to-left | 2 | lval, any ⇒ any |
*=, /+, %=, +=, -=, &=, ^=, |=, <<=, >>=, >>>= |
operate and assign | right-to-left | 2 | lval, any ⇒ any |
, | discard first operand, return second | left-to-right | 2 | any, any ⇒ any |
based on
number of operands
they expect
operators can be categorized as
unary / binary / ternary
operators
unary operators
convert a single expression into a single more complex expression
i++ // post-increment operator
binary operators
combine two expressions into a single more complex expression
i - j // substract operator
ternary operators
combines three expressions into a single expression
JavaScript supports only the conditional operator
a ? 'a' : 'b'; // returns one of two expressions depending on the condition
operand & result type
operators work with any type of values
BUT
some of them expect their operands to be of a specific type
&
most operators return a value of a specific type
operators usually convert the type of their operands as needed
'5' * '3' //=> 15
some operators
behave differently depending on the type of the
operands used with them
10 + 5 //=> 15
'Java' + 'Script' //=> "JavaScript"
15 + 'px' //=> "15px"
lvalue
lvalue is a historical term that means
“an expression that can legally appear
on the left side of an assignment expression”
lvalues in JavaScript
variables
properties of objects
elements of arrays
operators precedence
controls the order in which operations are performed
operators with higher precedence are performed
before those with lower precedence
1 + 2 * 7 //=> 15 `*` has higher precedence than `+` and `=`
has the lowest precedence
operator precedence can be overridden
with the explicit use of parentheses
(1 + 2) * 7 //=> 21
property access & invocation expressions
have higher precedence
than any operator
operator associativity
specifies the order in which operations of the same precedence
are performed
left-to-right associativity
operations are performed from left to right
30 - 10 - 5 //=> 15 -> is the same as ((30 - 10) - 5)
right-to-left associativity
operations are performed from left to right
var a, b, c;
a = b = c; //=> is equivalent to a = (b = (c = 5)) -> a, b, c all have the same value
order of evaluation
precedence & associativity
specify the order in which operations
are performed in a complex expression
BUT
they do not specify the order in
which the subexpressions are evaluated
JavaScript always evaluates expressions left-to-right
var a = b + c * d; // first the `a` is evaluated, then `b`, `c` & `d`
// then the values of `c` & `d` are multiplied,
// added to the value of `b` and assigned to the
// variable or property specified by expression `a`
* multiplication operator
/ division operator
% modulo (reminder) operator
- substraction operator
+ addition operator
+ / - / ++ / -- unary operators
& / | / ^ / ~ / << / >> / >>> bitwise operators
* / % -
multiplication / division / modulo / substracion
evaluate their operands
convert to numbers if necessary
perform arithmetic between values
5 * 3 //=> 15
15 / 3 //=> 5
15 % 2 //=> 1 -> 15 - (parseInt(15 / 2) * 2)
// -> (1st_operand - (integer(1st_operand / 2nd_operand) * 2nd_operand)
30 - 15 //=> 15
non-numeric operands that cannot convert to numbers convert to NaN
&
the result of the operation will also be NaN
+
binary + operator
adds numeric or concatenates string operands
10 + 5 //=> 15
"10" + "5" //=> "105"
"5" + 5 + 5 //=> "555"
false + 15 //=> 15
"15" + {} //=> "15[object Object]"
15 + undefined //=> NaN
10 + 5 + " years old" //=> "15 years old"
10 + (5 + " years old") //=> "105 years old"
if one operand is string or an object that converts to a string
+ operator gives priority to string concatenation
unary operators
+ / - / ++ / --
they modify the value of a single operand
to produce a new value
all have
high precedence
are
right-associative
&
convert their operand to a number
unary plus +
converts its operand to a number (or to NaN)
&
returns that converted value
+"15" //=> 15
if the operand is already a number it
does nothing
unary minus -
converts its operand to a number
&
returns the negation of its operand
-"15" //=> -15
increment ++
converts its operand to a number
adds 1
&
assigns the incremented value back
var count = 0;
console.log(count++); //=> 0 - post-increment
// assigns the result of `count + 1` expression
// returns initial `count` value which is `0`
console.log(count); //=> 1 - the `count` value is now `1`
console.log(++count); //=> 2 - pre-increment
// assigns the result of `count + 1` expression
// returns incremented `count` value which is `2`
console.log(count); //=> 2 - the `count` value is now `2`
its operand must be a lvalue
decrement --
converts its operand to a number
substracts 1
&
assigns the decremented value back
var count = 2;
console.log(count--); //=> 2 - post-decrement
// assigns the result of `count - 1` expression
// returns initial `count` value which is `2`
console.log(count); //=> 1 - the `count` value is now `1`
console.log(--count); //=> 0 - pre-decrement
// assigns the result of `count - 1` expression
// returns decremented `count` value which is `0`
console.log(count); //=> 0 - the `count` value is now `0`
like ++ operator
its operand must be a lvalue
bitwise operators
perform low-level manipulation of the bits
in the binary representation of numbers
expect integer operands
&
behave as if those values were represented as 32-bit integers
rather than 64-bit floating-point values
bitwise AND &
performs boolean AND on each bit of its integer arguments
15 // 32-bit -> 00000000000000000000000000001111
51 // 32-bit -> 00000000000000000000000000110011
// --------------------------------
15 & 51 //=> 3 32-bit -> 00000000000000000000000000000011
X | Y | X & Y |
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
AND operator's truth table is
bitwise OR |
performs boolean OR on each bit of its integer arguments
15 // 32-bit -> 00000000000000000000000000001111
51 // 32-bit -> 00000000000000000000000000110011
// --------------------------------
15 | 51 //=> 63 32-bit -> 00000000000000000000000000111111
X | Y | X | Y |
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 1 |
OR operator's truth table is
bitwise XOR ^
performs boolean eXclusive OR on each bit of its integer arguments
15 // 32-bit -> 00000000000000000000000000001111
51 // 32-bit -> 00000000000000000000000000110011
// --------------------------------
15 ^ 51 //=> 60 32-bit -> 00000000000000000000000000111100
X | Y | X ^ Y |
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
XOR operator's truth table is
bitwise NOT ~
operates by reversing all bits in the integer operand
15 // 32-bit -> 00000000000000000000000000001111
// --------------------------------
~15 //=> -16 32-bit -> 11111111111111111111111111110000
X | ~X |
0 | 1 |
1 | 0 |
NOT operator's truth table is
bitwise SHIFT LEFT <<
moves all bits in its first operand to the left by the number of places
specified in the second operand
15 // 32-bit -> 00000000000000000000000000001111
-15 // 32-bit -> 11111111111111111111111111110001
// --------------------------------
15 << 1 //=> 30 32-bit -> 00000000000000000000000000011110
15 << 15 //=> 491520 32-bit -> 00000000000001111000000000000000
15 << 31 //=> -2147483648 32-bit -> 10000000000000000000000000000000
-15 << 1 //=> -30 32-bit -> 11111111111111111111111111100010
bitwise SHIFT RIGHT WITH SIGN >>
moves all bits in its first operand to the right by the number of
places specified in the second operand
15 // 32-bit -> 00000000000000000000000000001111
-15 // 32-bit -> 11111111111111111111111111110001
// --------------------------------
15 >> 1 //=> 7 32-bit -> 00000000000000000000000000000111
15 >> 15 //=> 0 32-bit -> 00000000000000000000000000000000
-15 >> 15 //=> -1 32-bit -> 11111111111111111111111111111111
bitwise SHIFT RIGHT WITH ZERO FILL >>>
moves all bits in its first operand to the left by the number of places
specified in the second operand
15 // 32-bit -> 00000000000000000000000000001111
-15 // 32-bit -> 11111111111111111111111111110001
// --------------------------------
15 >>> 1 //=> 7 32-bit -> 00000000000000000000000000000111
15 >>> 15 //=> 0 32-bit -> 00000000000000000000000000000000
-15 >>> 15 //=> 131071 32-bit -> 00000000000000011111111111111111