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
var a = 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 = 5; //=> 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
relational operators
test the relationship between two values
&
return true or false
depending on whether that relationship exists
they always evaluate to a boolean value
which is often used to control the flow
of the program execution
equality & inequality
== / ===
both operators check if two values are the same
both accept operands of any type
both return true if operands are the same
&
both return false if they are different
BUT
they use two different definisions of sameness
strict equality ===
evaluates its operands and compares the two values
performing no type conversion
if the two values have different type ⇒ inequality
if both values are null or both undefined ⇒ equality
if both values are the boolean value true or both false ⇒ equality
if one or both values is NaN ⇒ inequality
if both values are numbers and have the same value ⇒ equality
if both values are strings and contain exactly the same 16-bit values in the same positions ⇒ equality
if both values refer to the same object / array / function ⇒ equality
if values refer to different objects even if both objects have identical properties ⇒ inequality
equality ==
acts like strict equality but is less strict
in case values have the same type
it will test them for strict equality
in case values are not the same type
it attemps some type conversion
&
tries the comparsion again
if the values have different types
it will use the following rules
if one value is null & the other is undefined ⇒ equality
if one value is number & the other is string - convert string to number & compare again
either value is true - convert to number (1) & compare again
either value is false - convert to number (0) & compare again
if one value is an object & the other is number or string - convert object to a primitive & compare again
any other combination of values ⇒ inequality
"1" === 1 //=> false
null === undefined //=> false
null === null //=> true
1 === NaN //=> false
NaN === NaN //=> false
true === 1 //=> false
true === true //=> true
false === 0 //=> false
false === false //=> true
0 === -0 //=> true
0 === 0 //=> true
var obj1 = { prop: 1 },
obj2 = { prop: 1 },
obj3 = obj1;
obj1 === obj2 //=> false
obj1 === obj3 //=> true
"1" == 1 //=> true
true == 1 //=> true
false == 0 //=> true
var arr = [0];
arr == 1 //=> false
arr == 0 //=> true
strict inequality !==
tests for the exact oposite of ===
it returns false if two values
are strictly equal to each other
&
returns true otherwise
inequality !=
tests for the exact oposite of ==
it returns false if two values
are equal to each other according to ==
&
returns true otherwise
comparsion operators
< / > / <= / =>
test the relative order
(numerical or alphabetical)
of their two operands
less than <
returns true if its first operand is less than its second operand
otherwise returns false
greater than >
returns true if its first operand is greater than its second operand
otherwise returns false
less than or equal <=
returns true if its first operand is less than or equal to its second operand
otherwise returns false
greater than or equal =>
returns true if its first operand is greater than or equal to its second operand
otherwise returns false
all of them support
operands of any type
BUT
comparison can be performed only on
numbers
&
strings
that's why operands that are not
numbers or strings are converted as follows
if either operand evaluates to an object it is converted to a primitive value
after conversion if both operands are strings
the two strings are compared using alphabetical order
otherwise
if at least one operand is not a string
both operands are converted to numbers and compared numerically
0 & -0 are considered equal
Infinity / -Infinity are larger / smaller than any number other than itself
if either operator is or converts to NaN ⇒ false
in operator
expects a left-side operand that is or can be converted to a string and
a right-side operand that is an object
evaluates to true if the left-side value is the name of a property
of the right-side object & to false otherwise
var course = {
title: 'JavaScript - The Basics',
chapter: 'Expressions & Operators'
};
'title' in course //=> true
'chapter' in course //=> true
'page' in course //=> false
var list = [ 'JavaScript - The Basics', 'Expressions & Operators', 'Page 57' ];
'0' in list //=> true -> `list` array has an element on `0` index
1 in list //=> true -> number is converted to string "1"
5 in list //=> false -> `list` array doesn't have an element on `5` index
instanceof operator
expects a left-side operand that is an object and a right-side
operand that identifies a class of objects
evaluates to true if the left-side object
is an instance of the right-side class & to false otherwise
var obj = {},
arr = [];
obj instanceof Object //=> true -> `obj` is an object
arr instanceof Array //=> true -> `obj` is an array
arr instanceof Object //=> true -> all arrays are instances of `Object`
function Course() {} //=> declaring a named function
var course = new Course(); //=> call it with the `new` keyword & assign to `course` variable
course instanceof Course //=> true -> `course` is an instance of `Course` class
course instanceof Object //=> true -> `Course` inherits from `Object`
logical operators
&& / || / !
perform boolean algebra
are often used in conjunction with the relational operators
to combine two relational expressions into one
more complex expression
logical AND &&
if its operands are boolean values
it performs boolean AND on its operands
&
returns true only if both operands are true
otherwise it returns false
true && true //=> true
false && true //=> false
true && false //=> false
false && false //=> false
1 == [1] && 1 === 1 //=> true (1 == 1) && (1 === 1)
// | |
// V V
// true && true
1 === [1] && 1 === 1 //=> ?
if its values are truthy / falsy values then it returns
a truthy value if both are truthy otherwise it returns a falsy value
it starts by evaluating its left operand
if this value is falsy the entire expression is falsy
and left operand value is returned
if value is truthy the overall value of the expression
depends on the value of the right operand whose value is the value returned
1 && 0 //=> 0
'' && 0 //=> ?
'XYZ' && 0 //=> ?
1 && '1' //=> "1"
1 && 0 //=> 0
'' && 0 //=> ""
'XYZ' && 0 //=> 0
1 && '1' //=> "1"
logical OR ||
it performs boolean AND on its operands
if its operands are truthy / falsy values
it returns a truthy value if either one of its operands is truthy
and returns a falsy value only if both are falsy values
it starts by evaluating the value of the left operand
if the value is truthy it will be the returned value
otherwise the right operand is evaluated whose value is the returned value
true || false //=> true
1 || 0 //=> 1
'' || 0 //=> 0
'XYZ' || 0 //=> "XYZ"
1 || '1' //=> "1"
logical NOT !
is a unary operator placed before a single operand
its purpose is to invert the boolean value of its operand
unlike && / || it converts its operand to a boolean value,
which means it always returns true or false
!true //=> false
!"" //=> true
!!1 //=> true -> any value can be converted to its boolean equivalent
// by applying this operator twice
JavaScript uses the = operator
to assign a value to a variable or a property
var course = {};
course.title = 'JavaScript - The Basics'; // set the property `title` of object `course`
// to 'JavaScript - The Basics'
var count = 0; // set variable `count` to 0
its left-side operand is expected to be an lvalue
variable name / object property / array element
the right-side operand is expected to be an arbitrary value of any type
assignament with operation
besides the normal = assignment operator
a number of other assignment operators
that provide shortcuts by combining assignment
with some other operation are supported
+= / -= / *= / /= / %= / <<= / >>= / >>>= / &= / |= / ^=
var c = 10;
c += 1 //=> 11 -> `c` is 11 (c = c + 1)
c *= 2 //=> 22 -> `c` is 22 (c = c * 2)
c /= 4 //=> 5.5 -> `c` is 5.5 (c = c / 4)
c -= 0.5 //=> 5 -> `c` is 5 (c = c - 0.5)
c %= 2 //=> 1 -> `c` is 1 (c = c % 2)
c <<= 1 //=> 2 -> `c` is 2 (c = c <<= 1)
c >>= 1 //=> 1 -> `c` is 1 (c = c >>= 1)
c >>>= 1 //=> 0 -> `c` is 0 (c = c >>= 0)
JavaScript
has the ability to interpret strings of JavaScript source code
this is done with the global function
eval()
eval("function sum(a, b) { return a + b; } sum(1, 1);") //=> 2
eval() expects one argument
if other value than string is passed as argument
is will return that value
if a string is passed
it will attempt to parse it as JavaScript code
and returns the value of the last expression or statement
conditional operator ? :
it's the only ternary operator available in JavaScript
its operands may be of any type
first operand goes before the ?
and is evaluated and interpreted as a boolean
if the value is truthy then the second operand which goes
between ? and : is evaluated and its value gets returned
if the values of the first operand is falsy
the third operand which goes after : is evaluated and its value gets returned
1 ? "truthy" : "falsy" //=> "truthy"
0 ? "truthy" : "falsy" //=> "falsy"
typeof operator
is a unary operator that is placed before its single operand
the operand can be of any type
its value is a a string that specifies the type of the operand
value | typeof value |
undefined | "undefined" |
null | "object" |
true or false | "boolean" |
any number or NaN | "number" |
any string | "string" |
any function | "function" |
delete | remove a property |
any nonfunction native object | "object" |
any host object | An implementation-defined string, but not “undefined”, “boolean”, “number”, or “string” |
delete operator
is a unary operator that attempts to delete the object
property or array element specified as its operand
a deleted property or array element is not set to the undefined value
when a property is deleted the property ceases to exist
var course = {
title: 'JavaScript - The Basics',
chapter: 'Expressions & Operators'
};
delete course.chapter
'chapter' in course //=> false
var list = [ 'JavaScript - The Basics', 'Expressions & Operators', 'Page 57' ];
delete list[0]
'0' in list //=> false
void operator
is a unary operator that appears before its single operand
which may be of any type
it evaluates its operand
then discards the value and returns undefined
var sum = function (a, b) {
return a + b;
}
void sum(1, 2); //=> undefined
void operator is commonly used in
browser javascript:URI
<a href="javascript:void(0)">Click here</a>
the browser evaluates the code in the URI
then replaces the contents of the page with the returned value
unless the returned value is undefined
comma operator ,
is a binary operator whose operands may be of any type
it evaluates the left operand
then evaluates the right operand and returns its value
var a, b, c;
a = 0, b = 1, c = 2; //=> 2
// is the same as
a = 0;
b = 1;
c = 2;