Skip to content

Commit 9cfba8f

Browse files
committed
types-grammar, ch2: adding discussion of string behaviors like concatenation and methods
1 parent faa253c commit 9cfba8f

File tree

4 files changed

+204
-13
lines changed

4 files changed

+204
-13
lines changed

types-grammar/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@
99
* [Foreword](foreword.md) (by TBA)
1010
* [Preface](../preface.md)
1111
* [Chapter 1: Primitives](ch1.md)
12-
* [Chapter 2: Value Behavior](ch2.md)
12+
* [Chapter 2: Value Behaviors](ch2.md)
1313
* Chapter 3: TODO

types-grammar/ch1.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,8 @@ The `string` type contains any value which is a collection of one or more charac
222222
myName = "Kyle";
223223
```
224224
225+
JS does not distinguish a single character as a different type as some languages do; `"a"` is a string just like `"abc"` is.
226+
225227
Strings can be delimited by double-quotes (`"`), single-quotes (`'`), or back-ticks (`` ` ``). The ending delimiter must always match the starting delimiter.
226228
227229
Strings have an intrinsic length which corresponds to how many code-points -- actually, code-units, more on that in a moment -- they contain.

types-grammar/ch2.md

Lines changed: 198 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,227 @@
11
# You Don't Know JS Yet: Types & Grammar - 2nd Edition
2-
# Chapter 2: Value Behavior
2+
# Chapter 2: Value Behaviors
3+
4+
| NOTE: |
5+
| :--- |
6+
| Work in progress |
37

48
So far, we've explored seven built-in primitive value types in JS: `null`, `undefined`, `boolean`, `string`, `number`, `bigint`, and `symbol`.
59

610
Chapter 1 was quite a lot to take in, much more involved than I bet most readers expected. If you're still catching your breath after reading all that, don't worry about taking a bit of a break before continuing on here!
711

812
Once you're clear headed and ready to move on, let's dig into certain behaviors implied by value types for all their respective values. We'll take a careful and closer look at all of these various behaviors.
913

10-
## Value Immutability
14+
## Primitive Immutability
15+
16+
All primitive values are immutable, meaning nothing in a JS program can reach into the contents of the value and modify it in any way.
1117

12-
All primitive values are immutable, meaning nothing in a JS program can reach into the inside of the value and modify it in any way.
18+
```js
19+
myAge = 42;
20+
21+
// later:
22+
23+
myAge = 43;
24+
```
1325

14-
New values are created through operations, but these do not modify the original value.
26+
The `myAge = 43` statement doesn't change the value. It reassigns a different value `43` to `myAge`, completely replacing the previous value of `42`.
27+
28+
New values are also created through various operations, but again these do not modify the original value:
1529

1630
```js
1731
42 + 1; // 43
1832

1933
"Hello" + "!"; // "Hello!"
2034
```
2135

22-
The values `43` and `"Hello!"` are new, distinct values from the `42` and `"Hello"` values, respectively.
36+
The values `43` and `"Hello!"` are new, distinct values from the previous `42` and `"Hello"` values, respectively.
2337

24-
// TODO
38+
Even a string value, which looks like merely an array of characters -- and array contents are typically mutable -- is immutable:
39+
40+
```js
41+
greeting = "Hello.";
42+
43+
greeting[5] = "!";
2544

26-
## Assignments Are Value Copies
45+
console.log(greeting); // Hello.
46+
```
2747

28-
Any assignment of a value from one variable/container to another is a *value-copy*.
48+
| WARNING: |
49+
| :--- |
50+
| In non-strict mode, assigning to a read-only property (like `greeting[5] = ..`) silently fails. In strict-mode, the disallowed assignment will throw an exception. |
51+
52+
The nature of primitive values being immutable is not affected *in any way* by how the variable or object property holding the value is declared. For example, whether `const`, `let`, or `var` are used to declare the `greeting` variable above, the string value it holds is immutable.
53+
54+
`const` doesn't create immutable values, it declares variables that cannot be reassigned (aka, immutable assignments) -- see the "Scope & Closures" title of this series for more information.
55+
56+
A property on an object may be marked as read-only -- with the `writable: false` descriptor attribute, as discussed in the "Objects & Classes" title of this series. But that still has no affect on the nature of the value, only on preventing the reassignment of the property.
57+
58+
### Primitives With Properties?
59+
60+
Additionally, properties *cannot* be added to any primitive values:
61+
62+
```js
63+
greeting = "Hello.";
64+
65+
greeting.isRendered = true;
66+
67+
greeting.isRendered; // undefined
68+
```
69+
70+
This snippet looks like it's adding a property `isRendered` to the value in `greeting`, but this assignment silently fails (even in strict-mode).
71+
72+
Property access is not allowed in any way on nullish primitive values `null` and `undefined`. But properties *can* be accessed on all other primitive values -- yes, that sounds counter-intuitive.
73+
74+
For example, all string values have a read-only `length` property:
75+
76+
```js
77+
greeting = "Hello.";
78+
79+
greeting.length; // 6
80+
```
81+
82+
`length` can not be set, but it can be accesses, and it exposes the number of code-units stored in the value (see "JS Character Encodings" in Chapter 1), which often means the number of characters in the string.
83+
84+
| NOTE: |
85+
| :--- |
86+
| Sort of. For most standard characters, that's true; one character is one code-point, which is one code-unit. However, as explained in Chapter 1, extended Unicode characters above code-point `65535` will be stored as two code-units (surrogate halves). Thus, for each such character, `length` will include `2` in its count, even though the character visually prints as one symbol. |
87+
88+
Non-nullish primitive values also have a couple of standard built-in methods that can be accessed:
89+
90+
```js
91+
greeting = "Hello.";
92+
93+
greeting.toString(); // "Hello." <-- redundant
94+
greeting.valueOf(); // "Hello."
95+
```
96+
97+
Additionally, most of the primitive value-types define their own methods with specific behaviors inherent to that type. We'll cover these later in this chapter.
98+
99+
| NOTE: |
100+
| :--- |
101+
| Technically, these sorts of property/method accesses on primitive values are facilitated by an implicit coercive behavior called *auto-boxing*, which we'll cover in the next chapter. |
102+
103+
## Primitive Assignments
104+
105+
Any assignment of a primitive value from one variable/container to another is a *value-copy*:
29106

30107
```js
31108
myAge = 42;
32109

33110
yourAge = myAge; // assigned by value-copy
111+
112+
myAge; // 42
113+
yourAge; // 42
114+
```
115+
116+
Here, the `myAge` and `yourAge` variables each have their own copy of the number value `42`.
117+
118+
| NOTE: |
119+
| :--- |
120+
| Inside the JS engine, it *may* be the case that only one `42` value exists in memory, and the engine points both `myAge` and `yourAge` variables at the shared value. Since primitive values are immutable, there's no danger in a JS engine doing so. But what's important to us as JS developers is, in our programs, `myAge` and `yourAge` act as if they have their own copy of that value, rather than sharing it. |
121+
122+
If we later reassign `myAge` to `43` (when I have a birthday), it doesn't affect the `42` that's still assigned to `yourAge`:
123+
124+
```js
125+
myAge++; // sort of like: myAge = myAge + 1
126+
127+
myAge; // 43
128+
yourAge; // 42 <-- unchanged
34129
```
35130

36-
Here, the `myAge` and `yourAge` variables each have their own copy of the number value `42`. That means if we later re-assign `myAge` to `43` when I have a birthday, it doesn't affect the `42` that's still assigned to `yourAge`.
131+
## String Behaviors
132+
133+
String values have a number of specific behaviors that every JS developer should be aware of.
134+
135+
As previously mentioned, string values have a `length` property that automatically exposes the number of characters (actually, code units). This property can only be accessed; attempts to set it are silently ignored.
136+
137+
### String Character Access
138+
139+
Though strings are not actually arrays, JS allows `[ .. ]` array-style access of its character at a numeric (`0`-based) index:
140+
141+
```js
142+
greeting = "Hello!";
143+
144+
greeting[4]; // "o"
145+
```
146+
147+
If the value/expression between the `[ .. ]` doesn't resolve to a number, the value will be implicitly coerced to its whole/integer numeric representation (if possible).
148+
149+
```js
150+
greeting["4"]; // "o"
151+
```
152+
153+
If the value/expression resolves to a number outside the integer range of `0` - `length - 1` (or `NaN`), or if it's not a `number` value-type, the access will instead be treated as a property access with the string equivalent property name. If the property access thus fails, the result is `undefined`.
154+
155+
| NOTE: |
156+
| :--- |
157+
| We'll cover coercion in-depth later in the book. |
158+
159+
### String Concatenation
160+
161+
Two or more string values can be concatenated (combined) into a new string value, using the `+` operator:
162+
163+
```js
164+
greeting = "Hello, " + "Kyle!";
165+
166+
greeting; // Hello, Kyle!
167+
```
168+
169+
The `+` operator will act as a string concatenation if either of the two operands (values on left or right sides of the operator) are already a string.
170+
171+
If one operand is a string and the other is not, the one that's not a string will be coerced to its string representation for the purposes of the concatenation.
172+
173+
### String Methods
174+
175+
Strings provide a whole slew of additional string-specific methods (as properties):
176+
177+
* `charAt(..)`: produces a new string value at the numeric index, similar to `[ .. ]`; unlike `[ .. ]`, the result is always a string, either the character at position `0` (if a valid number outside the indices range), or the empty string `""` (if missing/invalid index)
178+
179+
* `at(..)` is similar to `charAt(..)`, but negative indices count backwards from the end of the string
180+
181+
* `charCodeAt(..)`: returns the numeric code-unit (see "JS Character Encodings" in Chapter 1) at the specified index
182+
183+
* `codePointAt(..)`: returns the whole code-point starting at the specified index; if a surrogate pair is found there, the whole character (code-point) s returned
184+
185+
* `substr(..)` / `substring(..)` / `slice(..)`: produces a new string value that represents a range of characters from the original string; these differ in how the range's start/end indices are specified or determined
186+
187+
* `toUpperCase()`: produces a new string value that's all uppercase characters
188+
189+
* `toLowerCase()`: produces a new string value that's all lowercase characters
190+
191+
* `concat(..)`: produces a new string value that's the concatenation of the original string and all of the string value arguments passed in
192+
193+
* `indexOf(..)`: searches for a string value argument in the original string, optionally starting from the position specified in the second argument; returns the `0`-based index position if found, or `-1` if not found
194+
195+
* `lastIndexOf(..)`: like `indexOf(..)` but, from the end of the string (right in LTR locales, left in RTL locales)
196+
197+
* `includes(..)`: similar to `indexOf(..)` but returns a boolean result
198+
199+
* `search(..)`: similar to `indexOf(..)` but with a regular-expression matching as specified
200+
201+
* `trimStart()` / `trimEnd()` / `trim()`: produces a new string value with whitespace trimmed from the start of the string (left in LTR locales, right in RTL locales), or the end of the string (right in LTR locales, left in RTL locales), or both
202+
203+
* `repeat(..)`: produces a new string with the string argument value repeated the specified number of times
204+
205+
* `split(..)`: produces an array of string values as split at the specified string or regular-expression boundaries
206+
207+
* `padStart(..)` / `padEnd(..)`: produces a new string value with padding (default " " whitespace, but can be overriden) applied to either the start (left in LTR locales, right in RTL locales) or the end (right in LTR locales), left in RTL locales), so that the final string result is at least of a specified length
208+
209+
* `startsWith(..)` / `endsWith(..)`: checks either the start (left in LTR locales, right in RTL locales) or the end (right in LTR locales) of the original string for the string value argument; returns a boolean result
210+
211+
* `match(..)` / `matchAll(..)`: returns an array-like regular-expression matching result against the original string
212+
213+
* `replace(..)`: returns a new string with a replacement from the original string, of one or more matching occurrences of the specified regular-expression match
214+
215+
* `big()`, `blink()`, `bold()`, `fixed()`, `fontcolor()`, `fontsize()`, `italics()`, `link()`, `small()`, `strike()`, `sub()`, and `sup()`: historically, these were useful in generating HTML string snippets; they're now deprecated and should be avoided
216+
217+
### Static String Helpers
218+
219+
The following string utility functions are proviced directly on the `String` object, rather than as methods on individual string values:
220+
221+
* `String.fromCharCode(..)` / `String.fromCodePoint(..)`: produce a string from one or more arguments representing the code-units (`fromCharCode(..)`) or whole code-points (`fromCodePoint(..)`)
222+
223+
* `String.raw(..)`: a default template-tag function that allows interpolation on a template literal but prevents character escape sequences from being parsed, so they remain in their *raw* individual input characters from the literal
224+
225+
## Number Behaviors
37226

38227
// TODO

types-grammar/toc.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
* BigInteger Values
1818
* Symbol Values
1919
* Primitives Are Built-In Types
20-
* Chapter 2: Value Behavior
21-
* Value Immutability
22-
* Assignments Are Value Copies
20+
* Chapter 2: Value Behaviors
21+
* Primitive Immutability
22+
* Primitive Assignments
2323
* TODO

0 commit comments

Comments
 (0)