JS - Core - CL1 Flashcards
Identifiers and Reserved Words
https://www.w3schools.com/js/js_reserved.asp
Javascript types
https: //developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures
https: //www.w3schools.com/js/js_datatypes.asp
Reference vs value
Immutable Primitive Values and Mutable Object References There is a fundamental difference in JavaScript between primitive values ( undefined , null , booleans, numbers, and strings) and objects (including arrays and functions). Primitives are immutable: there is no way to change (or “mutate”) a primitive value. This is obvious for numbers and booleans—it doesn’t even make sense to change the value of a number. It is not so obvious for strings, however. 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. For example: var s = "hello"; // Start with some lowercase text s.toUpperCase(); // Returns "HELLO", but doesn't alter s s // => "hello": the original string has not changed
Primitives are also compared by value: two values are the same only if they have the
same value. This sounds circular for numbers, booleans, null , and undefined : there is
no other way that they could be compared. Again, however, it is not so obvious for
strings. If two distinct string values are compared, JavaScript treats them as equal if,
and only if, they have the same length and if the character at each index is the same.
Objects are different than primitives. First, they are mutable—their values can change: var o = { x:1 }; // Start with an object o.x = 2; // Mutate it by changing the value of a property o.y = 3; // Mutate it again by adding a new property var a = [1,2,3] // Arrays are also mutable a[0] = 0; // Change the value of an array element a[3] = 4; // Add a new array element
Objects are not compared by value: two objects are not equal even if they have the same
properties and values.
Objects are sometimes called reference types to distinguish them from JavaScript’s
primitive types. Using this terminology, object values are references, and we say that
objects are compared by reference: two object values are the same if and only if they
refer to the same underlying object.
As you can see from the code above, 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.
Property Attributes of an object
In addition to a name and value, properties have attributes that specify whether they
can be written, enumerated, and configured. In ECMAScript 3, there is no way to set
these attributes: all properties created by ECMAScript 3 programs are writable, enu-
merable, and configurable, and there is no way to change this. This section explains
the ECMAScript 5 API for querying and setting property attributes. This API is partic-
ularly important to library authors because:
• It allows them to add methods to prototype objects and make them nonenumer-
able, like built-in methods.
• It allows them to “lock down” their objects, defining properties that cannot be
changed or deleted.
For the purposes of this section, we are going to consider getter and setter methods of
an accessor property to be property attributes. Following this logic, we’ll even say that
the value of a data property is an attribute as well. Thus, we can say that a property has
a name and four attributes. The four attributes of a data property are value, writable,
enumerable, and configurable. Accessor properties don’t have a value attribute or a
writable attribute: their writability is determined by the presence or absence of a setter.
So the four attributes of an accessor property are get, set, enumerable, and configurable.
The ECMAScript 5 methods for querying and setting the attributes of a property use
an object called a property descriptor to represent the set of four attributes. A property
descriptor object has properties with the same names as the attributes of the property
it describes. Thus, the property descriptor object of a data property has properties
named value , writable , enumerable , and configurable . And the descriptor for an ac-
cessor property has get and set properties instead of value and writable . The writa
ble , enumerable , and configurable properties are boolean values, and the get and set
properties are function values, of course.
To obtain the property descriptor for a named property of a specified object, call
Object.getOwnPropertyDescriptor() :
// Returns {value: 1, writable:true, enumerable:true, configurable:true}
Object.getOwnPropertyDescriptor({x:1}, “x”);
// Now query the octet property of the random object defined above.
// Returns { get: /func/, set:undefined, enumerable:true, configurable:true}
Object.getOwnPropertyDescriptor(random, “octet”);
// Returns undefined for inherited properties and properties that don’t exist.
Object.getOwnPropertyDescriptor({}, “x”);
// undefined, no such prop
Object.getOwnPropertyDescriptor({}, “toString”); // undefined, inherited
As its name implies, Object.getOwnPropertyDescriptor() works only for own proper-
ties. To query the attributes of inherited properties, you must explicitly traverse the
prototype chain (see Object.getPrototypeOf() in §6.8.1).
To set the attributes of a property, or to create a new property with the specified at- tributes, call Object.defineProperty() , passing the object to be modified, the name of the property to be created or altered, and the property descriptor object: var o = {}; // Start with no properties at all // Add a nonenumerable data property x with value 1. Object.defineProperty(o, "x", { value : 1, writable: true, enumerable: false, configurable: true});
The property descriptor you pass to Object.defineProperty() does not have to include
all four attributes. If you’re creating a new property, then omitted attributes are taken
to be false or undefined . If you’re modifying an existing property, then the attributes
you omit are simply left unchanged. Note that this method alters an existing own
property or creates a new own property, but it will not alter an inherited property.
If you want to create or modify more than one property at a time, use Object.define
Properties() . The first argument is the object that is to be modified. The second ar-
gument is an object that maps the names of the properties to be created or modified to
the property descriptors for those properties.
We saw the ECMAScript 5 method Object.create() in §6.1. We learned there that the
first argument to that method is the prototype object for the newly created object. This
method also accepts a second optional argument, which is the same as the second
argument to Object.defineProperties() . If you pass a set of property descriptors to
Object.create() , then they are used to add properties to the newly created object.
Object.defineProperty() and Object.defineProperties() throw TypeError if the at-
tempt to create or modify a property is not allowed. This happens if you attempt to
add a new property to a nonextensible (see §6.8.3) object. The other reasons that these
methods might throw TypeError have to do with the attributes themselves. The writ-
able attribute governs attempts to change the value attribute. And the configurable
attribute governs attempts to change the other attributes (and also specifies whether a
property can be deleted). The rules are not completely straightforward, however. It is
possible to change the value of a nonwritable property if that property is configurable,
for example. Also, it is possible to change a property from writable to nonwritable even
if that property is nonconfigurable.
Object Attributes
Every object has associated prototype, class, and extensible attributes. The subsections
that follow explain what these attributes do and (where possible) how to query and
set them.
The prototype Attribute An object’s prototype attribute specifies the object from which it inherits properties. (Review §6.1.3 and §6.2.2 for more on prototypes and property inheritance.) This is such an important attribute that we’ll usually simply say “the prototype of o ” rather than “the prototype attribute of o .” Also, it is important to understand that when prototype appears in code font, it refers to an ordinary object property, not to the prototype attribute. The prototype attribute is set when an object is created. Recall from §6.1.3 that objects created from object literals use Object.prototype as their prototype. Objects created with new use the value of the prototype property of their constructor function as their prototype. And objects created with Object.create() use the first argument to that function (which may be null ) as their prototype. In ECMAScript 5, you can query the prototype of any object by passing that object to Object.getPrototypeOf() . There is no equivalent function in ECMAScript 3, but it is often possible to determine the prototype of an object o using the expression o.constructor.prototype . Objects created with a new expression usually inherit a constructor property that refers to the constructor function used to create the object. And, as described above, constructor functions have a prototype property that specifies the prototype for objects created using that constructor. This is explained in more detail in §9.2, which also explains why it is not a completely reliable method for determining an object’s prototype. Note that objects created by object literals or by Object.create() have a constructor property that refers to the Object() constructor. Thus, constructor.prototype refers to the correct prototype for object literals, but does not usually do so for objects created with Object.create() .
The class Attribute An object’s class attribute is a string that provides information about the type of the object. Neither ECMAScript 3 nor ECMAScript 5 provide any way to set this attribute, and there is only an indirect technique for querying it. The default toString() method (inherited from Object.prototype ) returns a string of the form: [object class] So to obtain the class of an object, you can invoke this toString() method on it, and extract the eighth through the second-to-last characters of the returned string. The tricky part is that many objects inherit other, more useful toString() methods, and to invoke the correct version of toString() , we must do so indirectly, using the Function.call() method (see §8.7.3). Example 6-4 defines a function that returns the class of any object you pass it.
The extensible Attribute
The extensible attribute of an object specifies whether new properties can be added to
the object or not. In ECMAScript 3, all built-in and user-defined objects are implicitly
extensible, and the extensibility of host objects is implementation defined. In ECMA-
Script 5, all built-in and user-defined objects are extensible unless they have been
converted to be nonextensible, and the extensibility of host objects is again implemen-
tation defined.
ECMAScript 5 defines functions for querying and setting the extensibility of an object.
To determine whether an object is extensible, pass it to Object.isExtensible() . To
make an object nonextensible, pass it to Object.preventExtensions() . Note that there
is no way to make an object extensible again once you have made it nonextensible. Also
note that calling preventExtensions() only affects the extensibility of the object itself.
If new properties are added to the prototype of a nonextensible object, the nonexten-
sible object will inherit those new properties.
The purpose of the extensible attribute is to be able to “lock down” objects into a known
state and prevent outside tampering. The extensible object attribute is often used in
conjunction with the configurable and writable property attributes, and
ECMAScript 5 defines functions that make it easy to set these attributes together.
Object.seal() works like Object.preventExtensions() , but in addition to making the
object nonextensible, it also makes all of the own properties of that object nonconfig-
urable. This means that new properties cannot be added to the object, and existing
properties cannot be deleted or configured. Existing properties that are writable can
still be set, however. There is no way to unseal a sealed object. You can use
Object.isSealed() to determine whether an object is sealed.
Object.freeze() locks objects down even more tightly. In addition to making the object
nonextensible and its properties nonconfigurable, it also makes all of the object’s own
data properties read-only. (If the object has accessor properties with setter methods,
these are not affected and can still be invoked by assignment to the property.) Use
Object.isFrozen() to determine if an object is frozen.
It is important to understand that Object.seal() and Object.freeze() affect only the
object they are passed: they have no effect on the prototype of that object. If you want
to thoroughly lock down an object, you probably need to seal or freeze the objects in
the prototype chain as well.
Type Conversion
JavaScript is very flexible about the types of values it requires. We’ve seen this for
booleans: when JavaScript expects a boolean value, you may supply a value of any type,
and JavaScript will convert it as needed. Some values (“truthy” values) convert to
true and others (“falsy” values) convert to false . The same is true for other types: if
JavaScript wants a string, it will convert whatever value you give it to a string. If Java-
Script wants a number, it will try to convert the value you give it to a number (or to
NaN if it cannot perform a meaningful conversion)
The primitive-to-primitive conversions shown in the table are relatively
straightforward. Conversion to boolean was already discussed in §3.3. Conversion to
strings is well-defined for all primitive values. Conversion to numbers is just a little
trickier. Strings that can be parsed as numbers convert to those numbers. Leading and
trailing spaces are allowed, but any leading or trailing nonspace characters that are not
part of a numeric literal cause the string-to-number conversion to produce NaN . Some
numeric conversions may seem surprising: true converts to 1, and false and the empty
string “” convert to 0.
Primitive-to-object conversions are straightforward: primitive values convert to their
wrapper object (§3.6) as if by calling the String() , Number() , or Boolean() constructor.
The exceptions are null and undefined : any attempt to use these values where an object
is expected raises a TypeError exception rather than performing a conversion.
Conversions and Equality
Because JavaScript can convert values flexibly, its == equality operator is also flexible
with its notion of equality. All of the following comparisons are true, for example:
null == undefined // These two values are treated as equal.
“0” == 0 // String converts to a number before comparing.
0 == false // Boolean converts to number before comparing.
“0” == false // Both operands convert to numbers before comparing.
§4.9.1 explains exactly what conversions are performed by the == operator in order to
determine whether two values should be considered equal, and it also describes the
strict equality operator === that does not perform conversions when testing for equality.
Keep in mind that convertibility of one value to another does not imply equality of
those two values. If undefined is used where a boolean value is expected, for example,
it will convert to false . But this does not mean that undefined == false . JavaScript
operators and statements expect values of various types, and perform conversions to
those types. The if statement converts undefined to false , but the == operator never
attempts to convert its operands to booleans.
Explicit Conversions
Although JavaScript performs many type conversions automatically, you may some-
times need to perform an explicit conversion, or you may prefer to make the conversions
explicit to keep your code clearer.
The simplest way to perform an explicit type conversion is to use the Boolean() ,
Number() , String() , or Object() functions. We’ve already seen these functions as con-
structors for wrapper objects (in §3.6). When invoked without the new operator, how-
ever, they work as conversion functions and perform the conversions summarized in
Table 3-2:
Number(“3”) // 3
String(false) // “false” Or use false.toString()
Boolean([]) // true
Object(3) // new Number(3)
Note that any value other than null or undefined has a toString() method and the
result of this method is usually the same as that returned by the String() function. Also
note that Table 3-2 shows a TypeError if you attempt to convert null or undefined to
an object. The Object() function does not throw an exception in this case: instead it
simply returns a newly created empty object.
Certain JavaScript operators perform implicit type conversions, and are sometimes
used for the purposes of type conversion. If one operand of the + operator is a string,
it converts the other one to a string. The unary + operator converts its operand to a
number. And the unary ! operator converts its operand to a boolean and negates it.
These facts lead to the following type conversion idioms that you may see in some code:
x + “” // Same as String(x)
+x // Same as Number(x). You may also see x-0
!!x // Same as Boolean(x). Note double !
Formatting and parsing numbers are common tasks in computer programs and Java-
Script has specialized functions and methods that provide more precise control over
number-to-string and string-to-number conversions.
Object to Primitive Conversions
Object-to-boolean conversions are trivial: all objects (including arrays and functions)
convert to true . This is so even for wrapper objects: new Boolean(false) is an object
rather than a primitive value, and so it converts to true .
Object-to-string and object-to-number conversions are performed by invoking a meth-
od of the object to be converted. This is complicated by the fact that JavaScript objects
have two different methods that perform conversions, and it is also complicated by
some special cases described below. Note that the string and number conversion rules
described here apply only to native objects. Host objects (defined by web browsers, for
example) can convert to numbers and strings according to their own algorithms.
All objects inherit two conversion methods. The first is called toString() , and its job
is to return a string representation of the object. The default toString() method does
not return a very interesting value (though we’ll find it useful in Example 6-4):
({x:1, y:2}).toString() // => “[object Object]”
Many classes define more specific versions of the toString() method. The toString()
method of the Array class, for example, converts each array element to a string and
joins the resulting strings together with commas in between. The toString() method
of the Function class returns an implementation-defined representation of a function.
In practice, implementations usually convert user-defined functions to strings of Java-
Script source code. The Date class defines a toString() method that returns a human-
readable (and JavaScript-parsable) date and time string. The RegExp class defines a
toString() method that converts RegExp objects to a string that looks like a RegExp
literal:
[1,2,3].toString() // => “1,2,3”
(function(x) { f(x); }).toString() // => “function(x) {\nf(x);\n}”
/\d+/g.toString() // => “/\d+/g”
new Date(2010,0,1).toString() // => “Fri Jan 01 2010 00:00:00 GMT-0800 (PST)”
The other object conversion function is called valueOf() . The job of this method is less
well-defined: it is supposed to convert an object to a primitive value that represents the
object, if any such primitive value exists. Objects are compound values, and most ob-
jects cannot really be represented by a single primitive value, so the default valueOf()
method simply returns the object itself rather than returning a primitive. Wrapper
classes define valueOf() methods that return the wrapped primitive value. Arrays,
functions, and regular expressions simply inherit the default method. Calling
valueOf() for instances of these types simply returns the object itself. The Date class
defines a valueOf() method that returns the date in its internal representation: the
number of milliseconds since January 1, 1970:
var d = new Date(2010, 0, 1); // January 1st, 2010, (Pacific time)
d.valueOf() // => 1262332800000
With the toString() and valueOf() methods explained, we can now cover object-to-
string and object-to-number conversions. Do note, however, that there are some special
cases in which JavaScript performs a different object-to-primitive conversion. These
special cases are covered at the end of this section.
To convert an object to a string, JavaScript takes these steps:
• If the object has a toString() method, JavaScript calls it. If it returns a primitive
value, JavaScript converts that value to a string (if it is not already a string) and
returns the result of that conversion. Note that primitive-to-string conversions are
all well-defined in Table 3-2.
• If the object has no toString() method, or if that method does not return a primitive
value, then JavaScript looks for a valueOf() method. If the method exists, Java-
Script calls it. If the return value is a primitive, JavaScript converts that value to a
string (if it is not already) and returns the converted value.
• Otherwise, JavaScript cannot obtain a primitive value from either toString() or
valueOf() , so it throws a TypeError.
To convert an object to a number, JavaScript does the same thing, but it tries the
valueOf() method first:
• If the object has a valueOf() method that returns a primitive value, JavaScript con-
verts (if necessary) that primitive value to a number and returns the result.
• Otherwise, if the object has a toString() method that returns a primitive value,
JavaScript converts and returns the value.
• Otherwise, JavaScript throws a TypeError.
The details of this object-to-number conversion explain why an empty array converts
to the number 0 and why an array with a single element may also convert to a number.
Arrays inherit the default valueOf() method that returns an object rather than a prim-
itive value, so array-to-number conversion relies on the toString() method. Empty
arrays convert to the empty string. And the empty string converts to the number 0. An
array with a single element converts to the same string that that one element does. If
an array contains a single number, that number is converted to a string, and then back
to a number.
The + operator in JavaScript performs numeric addition and string concatenation. If
either of its operands is an object, JavaScript converts the object using a special object-
to-primitive conversion rather than the object-to-number conversion used by the other
arithmetic operators. The == equality operator is similar. If asked to compare an object
with a primitive value, it converts the object using the object-to-primitive conversion.
The object-to-primitive conversion used by + and == includes a special case for Date
objects. The Date class is the only predefined core JavaScript type that defines mean-
ingful conversions to both strings and numbers. The 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 con-
version is not exactly the same as those explained above, however: the primitive value
returned by valueOf() or toString() is used directly without being forced to a number
or string.
The < operator and the other relational operators perform object-to-primitive conver-
sions like == does, but without the special case for Date objects: any object is converted
by trying valueOf() first and then toString() . Whatever primitive value is obtained is
used directly, without being further converted to a number or string.
Increment and Decrement Operators
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators
Variable Scoping
https://www.digitalocean.com/community/tutorials/understanding-variables-scope-hoisting-in-javascript
Context of calling (*.call(), *.apply(), *.bind())
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
Exception Handling
https://javascript.info/try-catch
Loops
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration
Object - Date
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date
Object - Array
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
Closures
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
ES6: let and scope
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
ES6: Arrow functions
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions