EXPRESSIONS AND OPERATIONS Flashcards
1) What is a JavaScript expression?:-
An expression is a phrase of JavaScript that can be evaluated to produce a value.
* A constant embedded literally in your program is a very simple kind of expression.
* A variable name is also a simple expression that evaluates to whatever value has been assigned to that variable.
2) What is a primary expression?:-
The simplest forms of expressions. They stand alone and do not include simpler expressions.
* Primary expressions in JavaScript are constant or literal values, certain language keywords,and variable
references.
- Literals are constant values that are embedded directly in your program. They look like these:
1.23 // A number literal
“hello” // A string literal
/pattern/ // A regular expression literal - Some of JavaScript’s reserved words are primary expressions:
true // Evalutes to the boolean true value
false // Evaluates to the boolean false value
null // Evaluates to the null value
this // Evaluates to the “current” object - Finally, the third type of primary expression is a reference to a variable, constant, or property of the
global object:
i // Evaluates to the value of the variable i.
sum // Evaluates to the value of the variable sum.
undefined // The value of the “undefined” property of the global object
3) When any identifier appears by itself in a program, JavaScript assumes it is a variable or constant or
property of the global object and looks up its value. If no variable with that name exists, an attempt to
evaluate a nonexistent variable throws?:-
a ReferenceError instead.
4) A function definition expression defines?:-
a JavaScript function, and the value of such an expression is the newly defined function.
- In a sense, a function definition expression is a “function literal” in the same way that an object
initializer is an “object literal.”
// This function returns the square of the value passed to it.
let square = function(x) { return x * x; };
5) What is property access expression?:-
A property access expression evaluates to the value of an object property or an array element.
6) JavaScript defines two syntaxes for property access. List them?:-
-> expression . identifier (objects)
-> expression [ expression ] (objects, and arrays)
let o = {x: 1, y: {z: 3}}; // An example object
let a = [o, 4, [5, 6]]; // An example array that contains the object
o.x // => 1: property x of expression o
o.y.z // => 3: property z of expression o.y
o[“x”] // => 1: property x of object o
a[1] // => 4: element at index 1 of expression a
a[2][“1”] / => 6: element at index 1 of expression a[2]
a[0].x // => 1: property x of expression a[0]
- A property access expression evaluates to the value of an object property or an array element.
- If the property name includes spaces or punctuation characters, or when it is a number (for arrays), you must use the square
bracket notation. Square brackets are also used when the property name is not static but is itself the result
of a computation.
7) ES2020 adds two new kinds of property access expressions. Name these Conditional Property Access?:-
-> expression ?. identifier
-> expression ?.[ expression ]
- In JavaScript, the values null and undefined are the only two values that do not have properties.
In a regular property access expression using . or [], you get a TypeError if the expression on the left
evaluates to null or undefined. You can use ?. and ?.[] syntax to guard against errors of this type. - Consider the expression a?.b. If a is null or undefined, then the expression evalu‐ ates to undefined without
any attempt to access the property b. If a is some other value, then a?.b evaluates to whatever a.b would
evaluate to (and if a does not have a property named b, then the value will again be undefined). - This form of property access expression is sometimes called “optional chaining” because it also works for
longer “chained” property access expressions like this one:
let a = { b: null };
a.b?.c.d // => undefined
- a is an object, so a.b is a valid property access expression. But the value of a.b is null, so a.b.c would
throw a TypeError. By using ?. instead of . we avoid the Type‐ Error, and a.b?.c evaluates to undefined. - This means that (a.b?.c).d will throw a TypeError, because that expression attempts to access a property of
the value unde fined. But—and this is a very important part of “optional chaining”—a.b?.c.d (without the
parentheses) simply evaluates to undefined and does not throw an error. - This is because property access with ?. is “short-circuiting”: if the subexpression to the left of ?.
evaluates to null or undefined, then the entire expression immediately evaluates to undefined without any
further property access attempts. - Of course, if a.b is an object, and if that object has no property named c, then a.b?.c.d will again throw a
TypeError, and we will want to use another conditional property access:
let a = { b: {} };
a.b?.c?.d // => undefined - Conditional property access is also possible using ?.[] instead of []. In the expres‐ sion a?.[b][c], if the
value of a is null or undefined, then the entire expression immediately evaluates to undefined, and
subexpressions b and c are never even eval‐ uated. If either of those expressions has side effects, the side
effect will not occur if a is not defined:
let a; // Oops, we forgot to initialize this variable!
let index = 0;
try {
a[index++]; // Throws TypeError } catch(e) {
index // => 1: increment occurs before TypeError is thrown
}
a?.[index++] // => undefined: because a is undefined
index // => 1: not incremented because ?.[] short-circuits
a[index++] // !TypeError: can’t index undefined.
8) In JavaScript, the values null and undefined are the only two values that do not have properties. In a
regular property access expression using . or [], you get a TypeError if the expression on the left evaluates
to null or undefined. What Conditional Property Access syntax can you use to guard against errors of this type?:-
-> ?. and
-> ?.[]
* Consider the expression a?.b. If a is null or undefined, then the expression evalu‐ ates to undefined without
any attempt to access the property b. If a is some other value, then a?.b evaluates to whatever a.b would
evaluate to (and if a does not have a property named b, then the value will again be undefined).
- In JavaScript, the values null and undefined are the only two values that do not have properties.
In a regular property access expression using . or [], you get a TypeError if the expression on the left
evaluates to null or undefined. You can use ?. and ?.[] syntax to guard against errors of this type. - This form of property access expression is sometimes called “optional chaining” because it also works for
longer “chained” property access expressions like this one:
let a = { b: null };
a.b?.c.d // => undefined
- a is an object, so a.b is a valid property access expression. But the value of a.b is null, so a.b.c would
throw a TypeError. By using ?. instead of . we avoid the Type‐ Error, and a.b?.c evaluates to undefined. - This means that (a.b?.c).d will throw a TypeError, because that expression attempts to access a property of
the value unde fined. But—and this is a very important part of “optional chaining”—a.b?.c.d (without the
parentheses) simply evaluates to undefined and does not throw an error. - This is because property access with ?. is “short-circuiting”: if the subexpression to the left of ?.
evaluates to null or undefined, then the entire expression immediately evaluates to undefined without any
further property access attempts. - Of course, if a.b is an object, and if that object has no property named c, then a.b?.c.d will again throw a
TypeError, and we will want to use another conditional property access:
let a = { b: {} };
a.b?.c?.d // => undefined - Conditional property access is also possible using ?.[] instead of []. In the expres‐ sion a?.[b][c], if the
value of a is null or undefined, then the entire expression immediately evaluates to undefined, and
subexpressions b and c are never even eval‐ uated. If either of those expressions has side effects, the side
effect will not occur if a is not defined:
let a; // Oops, we forgot to initialize this variable!
let index = 0;
try {
a[index++]; // Throws TypeError } catch(e) {
index // => 1: increment occurs before TypeError is thrown
}
a?.[index++] // => undefined: because a is undefined
index // => 1: not incremented because ?.[] short-circuits
a[index++] // !TypeError: can’t index undefined.
9) In ES2020, you can also invoke a function using Conditional Invocation ?.() instead of (). explain?:-
Normally when you invoke a function, if the expression to the left of the parentheses is null or unde fined or
any other non-function, a TypeError is thrown. With the new ?.() invoca‐ tion syntax, if the expression to the
left of the ?. evaluates to null or undefined, then the entire invocation expression evaluates to undefined and
no exception is thrown.
- Array objects have a sort() method that can optionally be passed a function argu‐ ment that defines the desired
sorting order for the array elements. Before ES2020, if you wanted to write a method like sort() that takes an
optional function argument, you would typically use an if statement to check that the function argument was
defined before invoking it in the body of the if:
function square(x, log) { // The second argument is an optional function
if (log) { // If the optional function is passed
log(x); // Invoke it
}
return x * x; // Return the square of the argument
}
- With this conditional invocation syntax of ES2020, however, you can simply write the function invocation using
?.(), knowing that invocation will only happen if there is actually a value to be invoked:
function square(x, log) { // The second argument is an optional function
log?.(x); // Call the function if there is one
return x * x; // Return the square of the argument
}
- Note, however, that ?.() only checks whether the lefthand side is null or undefined. It does not verify that
the value is actually a function. So the square() function in this example would still throw an exception if you
passed two numbers to it, for example. - Like conditional property access expressions, function invocation with ?.() is short-circuiting: if the value
to the left of ?. is null or undefined, then none of the argument expressions within the parentheses are
evaluated:
let f = null, x = 0;
try {
f(x++); // Throws TypeError because f is null
} catch(e) {
x // => 1: x gets incremented before the exception is thrown
}
f?.(x++) // => undefined: f is null, but no exception thrown
x // => 1: increment is skipped because of short-circuiting
10) Like conditional property access expressions, function invocation with ?.() is short-circuiting. Explain?:-
if the value to the left of ?. is null or undefined, then none of the argument expressions within the parentheses are
evaluated:
let f = null, x = 0;
try {
f(x++); // Throws TypeError because f is null
} catch(e) {
x // => 1: x gets incremented before the exception is thrown
}
f?.(x++) // => undefined: f is null, but no exception thrown
x // => 1: increment is skipped because of short-circuiting
11) Conditional invocation expressions with ?.() work just as well for methods as they do for functions.
But because method invocation also involves property access, it is worth taking a moment to be sure you
understand the differences between the following expressions
o.m()
o?.m()
o.m?.() ?:-
o.m() // Regular property access, regular invocation
o?.m() // Conditional property access, regular invocation
o.m?.() // Regular property access, conditional invocation
- In the first expression, o must be an object with a property m and the value of that property must be a
function. - In the second expression, if o is null or undefined, then the expression evaluates to undefined.
But if o has any other value, then it must have a property m whose value is a function. - And in the third expression, o must not be null or undefined. If it does not have a property m, or if the
value of that property is null, then the entire expression evaluates to undefined.
12) An object creation expression creates?:-
a new object and invokes a function (called a constructor) to initialize the properties of that object.
- Object creation expressions are like invocation expressions except that they are prefixed with the keyword new:
new Object()
new Point(2,3)
13) The assignment operators and a few other operators expect an operand of type lval. lvalue is a historical
term that means?:-
“an expression that can legally appear on the left side of an assignment expression.”
- In JavaScript, variables, properties of objects, and elements of arrays are lvalues.
14) Evaluating a simple expression like 2 * 3 never affects the state of your program, and any future
computation your program performs will be unaffected by that evaluation. Some expressions, however, have side
effects, and their evaluation may affect the result of future evaluations. What operations have side effect?:-
-> The assignment operators are the most obvious example: if you assign a value to a variable or property,
that changes the value of any expression that uses that variable or property.
-> The ++ and – increment and decrement operators are similar, since they perform an implicit assignment.
-> The delete operator also has side effects: deleting a property is like (but not the same as) assigning
undefined to the property.
-> No other JavaScript operators have side effects, but function invocation and object creation expressions
will have side effects if any of the operators used in the function or constructor body have side effects.
15) There is a natural ambiguity to expressions like -32. Depending on the relative precedence of unary minus
and exponentiation, that expression could mean (-3)2 or -(3**2). Different languages handle this differently,
and rather than pick sides, JavaScript simply?:-
makes it a syntax error to omit parentheses in this case, forcing you to write an unambiguous expression.
* The Math.pow() function has been available since the earliest versions of JavaScript, however, and it performs
exactly the same operation as the **(ES2016) operator.
16) If you are used to programming languages that distinguish between integer and floating-point numbers, you
might expect to get an integer result when you divide one integer by another. In JavaScript, however, all numbers
are?:-
floating-point, so all division operations have floating-point results: 5/2 evaluates to 2.5, not 2.
17) Technically, how does the + operator behaves?:-
-> If either of its operand values is an object, it converts it to a primitive using the object-to-primitive
algorithm. Date objects are converted by their toString() method, and all other objects are converted via
valueOf(), if that method returns a primitive value. However, most objects do not have a useful valueOf() method,
so they are converted via toString() as well.
-> After object-to-primitive conversion, if either operand is a string, the other is converted to a string and
concatenation is performed.
-> Otherwise, both operands are converted to numbers (or to NaN) and addition is performed.
Here are some examples:
1+2 // => 3: addition
“1” + “2” // => “12”: concatenation
“1” + 2 // => “12”: concatenation after number-to-string
1 + {} // => “1[objectobject]”: concatenation after object-to-string
true + true // => 2: addition after boolean-to-number
2 + null // => 2: addition after null converts to 0.
2 + undefined // => NaN: addition after undefined converts to NaN
18 ) It is important to note that when the + operator is used with strings and numbers, it may not be associative.
That is?:-
, the result may depend on the order in which operations are performed.
For example:
1 + 2 + “ blind mice” // => “3 blind mice”
1 + (2 + “ blind mice”) // => “12 blind mice”
- The first line has no parentheses, and the + operator has left-to-right associativity, so the two numbers are
added first, and their sum is concatenated with the string. In the second line, parentheses alter this order of
operations: the number 2 is concatenated with the string to produce a new string. Then the number 1 is
concatenated with the new string to produce the final result.
19 ) What are unary operands?:-
Unary operators modify the value of a single operand to produce a new value.
* In JavaScript, the unary operators all have high precedence and are all right-associative.
* The arithmetic unary operators described in this section (+, -, ++, and –) all convert their single operand
to a number, if necessary. Note that the punctuation characters + and - are used as both unary and binary
operators.
20 ) The return value of the ++ operator depends on its position relative to the operand. Explian?:-
When used before the operand, where it is known as the pre-increment operator, it increments the operand and
evaluates to the incremented value of that operand. When used after the operand, where it is known as the
post-increment operator, it increments its operand but evaluates to the unincremented value of that operand.
let i = 1, j = ++i; // i and j are both 2
let n = 1, m = n++; // n is 2, m is 1
- Note that the expression x++ is not always the same as x=x+1. The ++ operator never performs string
concatenation: it always converts its operand to a number and increments it. If x is the string “1”, ++x is the
number 2, but x+1 is the string “11”. - Also note that, because of JavaScript’s automatic semicolon insertion, you cannot insert a line break between
the post-increment operator and the operand that precedes it. If you do so, JavaScript will treat the operand as
a complete statement by itself and insert a semicolon before it. - the – operator is similar in nature.
21 ) The bitwise operators perform?:-
low-level manipulation of the bits in the binary representation of numbers.(Although they do not perform traditional
arithmetic opera‐ tions, they are categorized as arithmetic operators here because they operate on numeric
operands and return a numeric value.)
- Four of these operators perform Boolean algebra on the individual bits of the operands, behaving as if each
bit in each operand were a boolean value (1=true, 0=false). The other three bitwise operators are used to shift
bits left and right.
22 ) The bitwise operators expect integer operands and behave as if?:-
those values were represented as 32-bit integers rather than 64-bit floating-point values.
- These operators convert their operands to numbers, if necessary, and then coerce the numeric values to 32-bit
integers by dropping any fractional part and any bits beyond the 32nd. - Surprisingly, NaN, Infinity, and -Infinity all convert to 0 when used as operands of these bitwise operators.
- All of these bitwise operators except»_space;> can be used with regular number operands or with BigInt operands.
23 ) The shift operators require a?:-
right-side operand between 0 and 31.(After converting this operand to an unsigned 32-bit integer, they drop any bits beyond the 5th, which yields a number in the appropriate range).
- Surprisingly, NaN, Infinity, and -Infinity all convert to 0 when used as operands of these bitwise operators.
- All of these bitwise operators except»_space;> can be used with regular number operands or with BigInt operands.
24) How does the Bitwise AND (&) work?:-
The & operator performs a Boolean AND operation on each bit of its integer arguments. A bit is set in the result only if the corresponding bit is set in both operands. For example, 0x1234 & 0x00FF evaluates to 0x0034.