diff --git a/1-js/2-first-steps/03-structure/article.md b/1-js/2-first-steps/02-structure/article.md similarity index 100% rename from 1-js/2-first-steps/03-structure/article.md rename to 1-js/2-first-steps/02-structure/article.md diff --git a/1-js/2-first-steps/04-strict-mode/article.md b/1-js/2-first-steps/03-strict-mode/article.md similarity index 100% rename from 1-js/2-first-steps/04-strict-mode/article.md rename to 1-js/2-first-steps/03-strict-mode/article.md diff --git a/1-js/2-first-steps/05-variables/1-hello-variables/solution.md b/1-js/2-first-steps/04-variables/1-hello-variables/solution.md similarity index 100% rename from 1-js/2-first-steps/05-variables/1-hello-variables/solution.md rename to 1-js/2-first-steps/04-variables/1-hello-variables/solution.md diff --git a/1-js/2-first-steps/05-variables/1-hello-variables/task.md b/1-js/2-first-steps/04-variables/1-hello-variables/task.md similarity index 100% rename from 1-js/2-first-steps/05-variables/1-hello-variables/task.md rename to 1-js/2-first-steps/04-variables/1-hello-variables/task.md diff --git a/1-js/2-first-steps/05-variables/2-declare-variables/solution.md b/1-js/2-first-steps/04-variables/2-declare-variables/solution.md similarity index 100% rename from 1-js/2-first-steps/05-variables/2-declare-variables/solution.md rename to 1-js/2-first-steps/04-variables/2-declare-variables/solution.md diff --git a/1-js/2-first-steps/05-variables/2-declare-variables/task.md b/1-js/2-first-steps/04-variables/2-declare-variables/task.md similarity index 100% rename from 1-js/2-first-steps/05-variables/2-declare-variables/task.md rename to 1-js/2-first-steps/04-variables/2-declare-variables/task.md diff --git a/1-js/2-first-steps/05-variables/3-uppercast-constant/solution.md b/1-js/2-first-steps/04-variables/3-uppercast-constant/solution.md similarity index 100% rename from 1-js/2-first-steps/05-variables/3-uppercast-constant/solution.md rename to 1-js/2-first-steps/04-variables/3-uppercast-constant/solution.md diff --git a/1-js/2-first-steps/05-variables/3-uppercast-constant/task.md b/1-js/2-first-steps/04-variables/3-uppercast-constant/task.md similarity index 100% rename from 1-js/2-first-steps/05-variables/3-uppercast-constant/task.md rename to 1-js/2-first-steps/04-variables/3-uppercast-constant/task.md diff --git a/1-js/2-first-steps/05-variables/article.md b/1-js/2-first-steps/04-variables/article.md similarity index 100% rename from 1-js/2-first-steps/05-variables/article.md rename to 1-js/2-first-steps/04-variables/article.md diff --git a/1-js/2-first-steps/05-variables/variable-change.png b/1-js/2-first-steps/04-variables/variable-change.png similarity index 100% rename from 1-js/2-first-steps/05-variables/variable-change.png rename to 1-js/2-first-steps/04-variables/variable-change.png diff --git a/1-js/2-first-steps/05-variables/variable-change@2x.png b/1-js/2-first-steps/04-variables/variable-change@2x.png similarity index 100% rename from 1-js/2-first-steps/05-variables/variable-change@2x.png rename to 1-js/2-first-steps/04-variables/variable-change@2x.png diff --git a/1-js/2-first-steps/05-variables/variable.png b/1-js/2-first-steps/04-variables/variable.png similarity index 100% rename from 1-js/2-first-steps/05-variables/variable.png rename to 1-js/2-first-steps/04-variables/variable.png diff --git a/1-js/2-first-steps/05-variables/variable@2x.png b/1-js/2-first-steps/04-variables/variable@2x.png similarity index 100% rename from 1-js/2-first-steps/05-variables/variable@2x.png rename to 1-js/2-first-steps/04-variables/variable@2x.png diff --git a/1-js/2-first-steps/07-types/1-string-quotes/solution.md b/1-js/2-first-steps/05-types/1-string-quotes/solution.md similarity index 100% rename from 1-js/2-first-steps/07-types/1-string-quotes/solution.md rename to 1-js/2-first-steps/05-types/1-string-quotes/solution.md diff --git a/1-js/2-first-steps/07-types/1-string-quotes/task.md b/1-js/2-first-steps/05-types/1-string-quotes/task.md similarity index 100% rename from 1-js/2-first-steps/07-types/1-string-quotes/task.md rename to 1-js/2-first-steps/05-types/1-string-quotes/task.md diff --git a/1-js/2-first-steps/05-types/article.md b/1-js/2-first-steps/05-types/article.md new file mode 100644 index 00000000..f52bf0c5 --- /dev/null +++ b/1-js/2-first-steps/05-types/article.md @@ -0,0 +1,242 @@ +# Data types + +There are 7 data types in JavaScript. + +Here we will get the common understanding of them. In the next chapters we'll talk about each type in detail. + +[cut] + +## A number + +```js +let n = 123; +n = 12.345; +``` + +A *number* type serves both for integer and floating point numbers. + +There are many operations for numbers, e.g. multiplication `*`, division `/`, addition `+`, substraction `-` and so on. + +Besides regular numbers there are so-called "special numeric values" which also belong to that type: `Infinity`, `-Infinity` and `NaN`. + +- `Infinity` represents the mathematical [Infinity](https://en.wikipedia.org/wiki/Infinity). It is a value that's greater than any number. + + We can get it as a result of division by zero: + + ```js run + alert( 1 / 0 ); // Infinity + ``` + + Or just mention it in the code directly: + + ```js run + alert( Infinity ); // Infinity + ``` +- `NaN` represents a computational error. It is a result of an incorrect or an undefined mathematical operation, for instance: + + ```js run + alert( "not a number" / 2 ); // NaN + ``` + + `NaN` is sticky. Any further operation on `NaN` would give `NaN`: + + ```js run + alert( "not a number" / 2 + 5 ); // NaN + 5 is still NaN + ``` + + So, in a long mathematical expression if we have `NaN` in one place, it propagates to the whole result. + +```smart header="Mathematical operations are safe" +Doing maths is safe in JavaScript. We can do anything: divide by zero, treat non-numeric strings as numbers, etc. + +The script will never stop with a fatal error ("die"). At worst we'll get `NaN` as the result. +``` + +Special numeric values formally belong to the "number" type. Of course they are not numbers in a common sense of this word. + +We'll see more into working with numbers in the chapter . + +## A string + +```js +let str = "Hello"; +let str2 = 'Single quotes are ok too'; +let phrase = `can embed ${str}`; +``` + +In JavaScript, there are 3 types of quotes. + +1. Double quotes: `"Hello"`. +2. Single quotes: `'Hello'`. +3. Backticks: `Hello`. + +Double and single quotes are similar, "simple" quotes. + +Backticks are "extended functionality" quotes. They allow to embed variables and expressions into a string by wrapping them in `${…}`, for example: + +```js run +let name = "John"; + +// embed variable +alert( `Hello, ${name}!` ); // Hello, John! + +// embed expression +alert( `the result is ${1 + 2}` ); // the result is 3 +``` + +The expression inside `${…}` is evaluated and the result becomes a part of the string. We can put anything there: a variable like `name` or an arithmetical expression like `1 + 2` or something more complex. + +We'll cover strings more thoroughly in the chapter . + +```smart header="There is no *character* type." +In some languages, there is a special "character" type for a single character. For example, in the C language it is `char`. + +In JavaScript, there is no such type. There's only one type: `string`. A string may consist of only one character or many of them. +``` + +## A boolean (logical) + +The boolean type has only two values: `true` and `false`. + +This type is commonly used to store yes/no values. + +For instance: + +```js no-beautify +let checked = true; // the form field is checked +checked = false; // the form field is not checked +``` + +Boolean values also come as the result of comparisons: + +```js run +let isGreater = 4 > 1; + +alert( isGreater ); // true (the comparison result is "yes") +``` + +We'll cover booleans more deeply while discussing logical operators. + +## The "null" value + +The special `null` value does not belong to any type described above. + +It forms a separate type of its own, which contains only the `null` value: + +```js +let age = null; +``` + +In JavaScript `null` is not a "reference to a non-existing object" or a "null pointer" like in some other languages. + +It's just a special value which has the sense of "nothing", "empty" or "value unknown". + +The code above states that the `age` is unknown or empty for some reason. + +## The "undefined" value + +The special value `undefined` stands apart. It makes a type of its own, just like `null`. + +The sense of `undefined` is "value is not assigned". + +If a variable is declared, but not assigned, then its value is exactly `undefined`: + +```js run +let x; + +alert( x ); // shows "undefined" +``` + +Technically, it is possible to assign to `undefined`: + +```js run +let x = 123; + +x = undefined; + +alert( x ); // "undefined" +``` + +...But it's not recommended to do that. Normally, we use `null` to write an "empty" or an "unknown" value into the variable, and `undefined` is only used for checks, to see if the variable is assigned or similar. + +## Objects and Symbols + +The `object` type is special. + +All other types are called "primitive", because their values can contain only a single thing (be it a string or a number or whatever). + +In contrast, objects are used to store collections data and more complex entities. We'll deal with them later after we know enough about primitives. + +The `symbol` type is used to create unique identifiers, mainly used to store data in objects. We'll return to them as soon as we cover objects. + + +[todo when ? chapter?] +[todo move tasks] + +## The typeof operator [#type-typeof] +[todo we need typeof in types] + +The `typeof` operator returns the type of the argument. It's useful when we want to process values of different types differently, or just want to make a quick check. + +It supports two forms of syntax: + +1. As an operator: `typeof x`. +2. Function style: `typeof(x)`. + +In other words, it works both with the brackets or without them. The result is the same. + +The call to `typeof x` returns a string, which has the type name: + +```js +typeof undefined // "undefined" + +typeof 0 // "number" + +typeof true // "boolean" + +typeof "foo" // "string" + +typeof Symbol("id") // "symbol" + +*!* +typeof Math // "object" (1) +*/!* + +*!* +typeof null // "object" (2) +*/!* + +*!* +typeof alert // "function" (3) +*/!* +``` + +The last three lines may be a little unobvious so here's explanations: + +1. `Math` is a built-in object that provides mathematical operations. We will learn it in the chapter . Here it servers as an example, nothing more. +2. The result of `typeof null` equals to `"object"`. That's wrong. It is an officially recognized error in `typeof`, kept for compatibility. Of course, `null` is not an object. It is a special value with a separate type of its own. So, again, that's an error in the language. +3. The result of `typeof alert` is `"function"`, because `alert` is a function of the language. We'll study functions in the near future and see that actually functions belong to the object type. But `typeof` treats them differently. That's very convenient in practice. + + +## Summary + +There are 7 basic types in JavaScript. + +- `number` for numbers of any kind, can convert into it using `Number(value)`. +- `string` for strings and characters, can convert into it using `String(value)`. +- `boolean` for `true`/`false`, can convert into it using `Boolean(value)`. +- `null` for unknown values (a standalone type that has a single value `null`). +- `undefined` for unassigned values (a standalone type that has a single value `undefined`). +- `object` for more complex data structures. +- `symbol` for unique identifiers. + +The `typeof` operator allows to see which type is stored in the variable. + +- Two forms: `typeof x` or `typeof(x)`. +- Returns a string with the name of the type, like `"string"`. +- Mistreats `null` as an `object` -- the old official error in the language. + +In nearest chapters we'll concentrate on understanding how to operate on primitives and once we're familiar with that, then we'll move on to objects. + + + diff --git a/1-js/2-first-steps/08-type-conversions/1-primitive-conversions-questions/solution.md b/1-js/2-first-steps/06-type-conversions/1-primitive-conversions-questions/solution.md similarity index 100% rename from 1-js/2-first-steps/08-type-conversions/1-primitive-conversions-questions/solution.md rename to 1-js/2-first-steps/06-type-conversions/1-primitive-conversions-questions/solution.md diff --git a/1-js/2-first-steps/08-type-conversions/1-primitive-conversions-questions/task.md b/1-js/2-first-steps/06-type-conversions/1-primitive-conversions-questions/task.md similarity index 100% rename from 1-js/2-first-steps/08-type-conversions/1-primitive-conversions-questions/task.md rename to 1-js/2-first-steps/06-type-conversions/1-primitive-conversions-questions/task.md diff --git a/1-js/2-first-steps/08-type-conversions/article.md b/1-js/2-first-steps/06-type-conversions/article.md similarity index 74% rename from 1-js/2-first-steps/08-type-conversions/article.md rename to 1-js/2-first-steps/06-type-conversions/article.md index a9410a40..7d6db4db 100644 --- a/1-js/2-first-steps/08-type-conversions/article.md +++ b/1-js/2-first-steps/06-type-conversions/article.md @@ -12,6 +12,14 @@ message = 123456; There are also cases when we need to explicitly convert between types to ensure that we store the right data the right way or to use special features of a certain type. +[cut] + +```smart header="No objects here" +In this chapter we don't cover objects yet. They provide special facilities for conversion, interesting, but we'd better understand primitives first, then extend to objects in the next steps. +``` + +[todo where? link?] + ## ToString The string conversion happens when we need a string form of a value. @@ -21,7 +29,7 @@ For example, `alert` does it: ```js run let a = true; -alert( a ); // "true" +alert(a); // "true" ``` We can also use a call `String(value)` function for that: @@ -134,56 +142,17 @@ alert( Boolean(" ") ); // also true (any non-empty string is true) ``` ```` -````warn header="Empty objects are truthy" -All objects become `true`: - -```js run -alert( Boolean([]) ); // true, even if empty array -alert( Boolean({}) ); // true, even if empty object -``` -```` - - -## ToPrimitive - -A string or numeric conversion of an object is a two-stage process. The object is first converted to a primitive value, and then ToString/ToNumber rules are applied to it. - -The conversion is customizable on a per-object basis, so we'll study it later when we go deeper into objects. [todo in the chapter?] - -Examples: - -- When a plain object is converted into a string, is becomes `[object Object]`: - - ```js run - alert( {} ); // [object Object] - alert( {name: "John"} ); // [object Object] - ``` - -- An array becomes a comma-delimited list of items: - - ```js run - let arr = [1, 2, 3]; - - alert( arr ); // 1,2,3 - alert( String(arr) === '1,2,3' ); // true - ``` - -We'll return to it in the chapter [todo]. - -```smart header="ToBoolean is always true" -Here `ToBoolean` was not mentioned, because it provides no customizability for objects - -The rule is simple: all objects are truthy. -``` - ## Summary -There exist three most widely used type conversions: to string, to number and to boolean. -The conversion to string is usully obvious for primitive values and depends on the object type for objects. For instance, arrays turn into a comma-delimited list of elements. +- `ToString` -- happens in output, can be called with `String(value)`. -To number follows the rules: +The conversion to string is usully obvious for primitive values. + +- `ToNumber` -- happens in math operations, can be called with `Number(value)`. + +The conversion follows the rules: | Value | Becomes... | |-------|-------------| @@ -192,7 +161,7 @@ To number follows the rules: |true / false | `1 / 0` | | `string` | The string is read "as is", whitespaces from both sides are ignored. An empty string is `0`. An error gives `NaN`. | -To boolean: +- ToBoolean -- happens in logical operatiosn, can be called with `Boolean(value)`. | Value | Becomes... | |-------|-------------| @@ -204,5 +173,5 @@ Most of these rules are easy to understand and memorize. The notable exceptions - `undefined` is `NaN` as a number. - `"0"` is true as a boolean. -Objects can define their own methods of converting to a string or a number, we'll see them later. But they can't redefine the conversion to boolean. +Objects are not covered here, we'll return to them in the special object-only chapter. diff --git a/1-js/2-first-steps/09-operators/1-increment-order/solution.md b/1-js/2-first-steps/07-operators/1-increment-order/solution.md similarity index 100% rename from 1-js/2-first-steps/09-operators/1-increment-order/solution.md rename to 1-js/2-first-steps/07-operators/1-increment-order/solution.md diff --git a/1-js/2-first-steps/09-operators/1-increment-order/task.md b/1-js/2-first-steps/07-operators/1-increment-order/task.md similarity index 100% rename from 1-js/2-first-steps/09-operators/1-increment-order/task.md rename to 1-js/2-first-steps/07-operators/1-increment-order/task.md diff --git a/1-js/2-first-steps/09-operators/2-assignment-result/solution.md b/1-js/2-first-steps/07-operators/2-assignment-result/solution.md similarity index 100% rename from 1-js/2-first-steps/09-operators/2-assignment-result/solution.md rename to 1-js/2-first-steps/07-operators/2-assignment-result/solution.md diff --git a/1-js/2-first-steps/09-operators/2-assignment-result/task.md b/1-js/2-first-steps/07-operators/2-assignment-result/task.md similarity index 100% rename from 1-js/2-first-steps/09-operators/2-assignment-result/task.md rename to 1-js/2-first-steps/07-operators/2-assignment-result/task.md diff --git a/1-js/2-first-steps/09-operators/article.md b/1-js/2-first-steps/07-operators/article.md similarity index 100% rename from 1-js/2-first-steps/09-operators/article.md rename to 1-js/2-first-steps/07-operators/article.md diff --git a/1-js/2-first-steps/07-types/4-sum-array/solution.md b/1-js/2-first-steps/07-types/4-sum-array/solution.md deleted file mode 100644 index 00b8cf79..00000000 --- a/1-js/2-first-steps/07-types/4-sum-array/solution.md +++ /dev/null @@ -1,13 +0,0 @@ - - -```js run -let salaries = [ 100, 160, 130 ]; - -let sum = 0; -for(let salary of salaries) { - sum += salary; -} - -alert( sum ); // 390 -``` - diff --git a/1-js/2-first-steps/07-types/4-sum-array/task.md b/1-js/2-first-steps/07-types/4-sum-array/task.md deleted file mode 100644 index 05e8869a..00000000 --- a/1-js/2-first-steps/07-types/4-sum-array/task.md +++ /dev/null @@ -1,13 +0,0 @@ -importance: 5 - ---- - -# Sum the array - -Write the code to get the sum of the array using `for..of` loop and store in the variable `sum`: - -```js -let salaries = [ 100, 160, 130 ]; -``` - -Should be `390` here. diff --git a/1-js/2-first-steps/07-types/article.md b/1-js/2-first-steps/07-types/article.md deleted file mode 100644 index 32b16d96..00000000 --- a/1-js/2-first-steps/07-types/article.md +++ /dev/null @@ -1,425 +0,0 @@ -# Data types - -There are 7 data types in JavaScript. - -Here we will get the common understanding of them. In the next chapters we'll talk about each type in detail. - -[cut] - -## A number - -```js -let n = 123; -n = 12.345; -``` - -A *number* type serves both for integer and floating point numbers. - -There are many operations for numbers, e.g. multiplication `*`, division `/`, addition `+`, substraction `-` and so on. - -Besides regular numbers there are so-called "special numeric values" which also belong to that type: `Infinity`, `-Infinity` and `NaN`. - -- `Infinity` represents the mathematical [Infinity](https://en.wikipedia.org/wiki/Infinity). It is a value that's greater than any number. - - We can get it as a result of division by zero: - - ```js run - alert( 1 / 0 ); // Infinity - ``` - - Or just mention it in the code directly: - - ```js run - alert( Infinity ); // Infinity - ``` -- `NaN` represents a computational error. It is a result of an incorrect or an undefined mathematical operation, for instance: - - ```js run - alert( "not a number" / 2 ); // NaN - ``` - - `NaN` is sticky. Any further operation on `NaN` would give `NaN`: - - ```js run - alert( "not a number" / 2 + 5 ); // NaN - ``` - - So, in a long mathematical expression if we have `NaN` in one place, it propagates to the whole result. - -```smart header="Mathematical operations are safe" -Doing maths is safe in JavaScript. We can do anything: divide by zero, treat non-numeric strings as numbers, etc. - -The script will never stop ("die") on that. At worst we'll get `NaN` as the result. -``` - -Special numeric values formally belong to the "number" type. Of course they are not numbers in a common sense of this word. - -We'll see more into working with numbers in the chapter . - -## A string - -```js -let str = "Hello"; -let str2 = 'Single quotes are ok too'; -let phrase = `can embed ${str}`; -``` - -In JavaScript, there are 3 types of quotes. - -1. Double quotes: `"Hello"`. -2. Single quotes: `'Hello'`. -3. Backticks: `Hello`. - -Double and single quotes are similar, "simple" quotes. - -Backticks are "extended functionality" quotes. They allow to embed variables and expressions into a string by wrapping them in `${…}`, for example: - -```js run -let name = "John"; - -// embed variable -alert( `Hello, ${name}!` ); // Hello, John! - -// embed expression -alert( `the result is ${1 + 2}` ); // the result is 3 -``` - -The expression inside `${…}` is evaluated and the result becomes a part of the string. We can put anything there: a variable like `name` or an arithmetical expression like `1 + 2` or something more complex. - -We'll cover strings more thoroughly in the chapter . - -```smart header="There is no *character* type." -In some languages, there is a special "character" type for a single character. For example, in the C language it is `char`. - -In JavaScript, there is no such type. There's only one type: `string`. A string may consist of only one character or many of them. -``` - -## A boolean (logical) - -The boolean type has only two values: `true` and `false`. - -This type is commonly used to store yes/no values. - -For instance: - -```js no-beautify -let checked = true; // the form field is checked -checked = false; // the form field is not checked -``` - -Boolean values also come as the result of comparisons: - -```js run -let isGreater = 4 > 1; - -alert( isGreater ); // true (the comparison result is "yes") -``` - -We'll cover booleans more deeply while discussing logical operators. - -## The "null" value - -The special `null` value does not belong to any type described above. - -It forms a separate type of its own, which contains only the `null` value: - -```js -let age = null; -``` - -In JavaScript `null` is not a "reference to a non-existing object" or a "null pointer" like in some other languages. - -It's just a special value which has the sense of "nothing", "empty" or "value unknown". - -The code above states that the `age` is unknown or empty for some reason. - -## The "undefined" value - -The special value `undefined` stands apart. It makes a type of its own, just like `null`. - -The sense of `undefined` is "value is not assigned". - -If a variable is declared, but not assigned, then its value is exactly `undefined`: - -```js run -let x; - -alert( x ); // shows "undefined" -``` - -Technically, it is possible to assign to `undefined`: - -```js run -let x = 123; - -x = undefined; - -alert( x ); // "undefined" -``` - -...But it's not recommended to do that. Normally, we use `null` to write an "empty" or an "unknown" value into the variable, and `undefined` is only used for checks, to see if the variable is assigned or similar. - - -## Objects - -The `object` type is special. - -All other types are called "primitive", because their values can contain only a single thing (be it a string or a number or whatever). - -In contrast, objects are used to store *keyed collections* of various data and more complex entities. - -An object is defined with the figure brackets `{…}` with an optional list of "key: value" pairs. In programming that's sometimes called an "associative array" or a "hash". - -A `key` is a string, `value` can be anything. - -For instance, here we create a `user` object with two properties: - -```js -let user = { // an object - name: "John", // key "name" has value "John" - age: 30 // key "age" has value 30 -}; -``` - -The `user` object can be imagined as a cabinet with two signed files labelled "name" and "age". - -![user object](object-user.png) - -Both values (also called "fields" or "properties") are accessible using the dot notation: - -```js -// get fields of the object: -alert( user.name ); // John -alert( user.age ); // 30 -``` - -Also we can add new information to the user any time later: - -```js -user.isAdmin = true; -``` - -![user object 2](object-user-isadmin.png) - -...Or remove it with the help of `delete` operator: - -```js -delete user.age; -``` - -![user object 3](object-user-delete.png) - -If the string which denotes the key (also called a "property name") has multiple words, then the dot notation won't work: - -```js -// this would give a syntax error -user.likes to swim? = true; -``` - -That's because, the dot requires the property name to be a valid variable identifier. That is: no spaces and other limitations. - -There's a "square bracket notation" that works with any string: - -```js -user["likes to swim?"] = true; -``` - -Square brackets are also the way to access a property by the name from the variable: - -```js -let key = "likes to swim?"; -user[key] = true; // same as above -``` - -Here we have a variable `key` which contains the property name, probably evaluated or calculated at run-time. - -Most of time, the dot is used to access object properties, but when we need a complex property name or to pass the name as a variable, then -- we go square brackets. - -What we've just seen is called a "plain object", or just `Object`. - -There are many other kinds of objects in Javascript: - -- `Array` to store ordered data collections, -- `Date` to store the information about the date and time, -- `Error` to store the information about an error. -- ...And so on. - -Sometimes people say something like "Array type" or "Date type", but formally they are not types of their own, but belong to a single "object" data type. And they extend it in various ways. - -Objects in JavaScript are very powerful. Here we've just scratched the surface of the topic that is really huge. We'll be closely working with objects and learning more about them in further parts of the tutorial. - -````smart header="A trailing comma" - -[todo: move to 4-object ?] -Experienced developers sometimes add one more comma to the end of an object, like this: - -```js -let user = { - name: "John", - age: 30, - isAdmin: true*!*,*/!* // extra comma -}; -``` - -That's called a "trailing comma" and is allowed by the language. - -Sometimes the reason is pure lazyness: when in the development process the last property becomes unneeded and is removed, the programmer forgets to delete the comma at the end of newly last one. - -But from the other side that "lazyness" is justified, because the same line can be safely moved between objects -- from the first position to the middle or to the last -- without bookkeeping commas. That's a good thing. - -Actual decision whether to add trailing commas or not depends on you. Some people like them, some find them ugly. -```` - -## Arrays - -As we’ve just seen, objects in Javascript store arbitrary keyed values. - -But quite often we find that we need an *ordered collection*, where we have a 1st, a 2nd, a 3rd element and so on. For example, we need that to store a list of something: users, goods, HTML elements etc. It not convenient to use an object here, because it provides no methods to manage the order of elements. We can’t easily access the n-th element in an object. Also we can’t insert a new property “before” the existing ones, and so on. Objects are just not meant for such use. - -There exists a special data structure named "an array", to store ordered collections. - -An array is created using square brackets: - -```js -let empty = []; // empty array - -let fruits = ["Apple", "Orange", "Plum"]; // array with 3 values -``` - -Individual items are accessed using brackets `[]`, the first item has zero index: - -```js run -let fruits = ["Apple", "Orange", "Plum"]; // array with 3 values - -alert( fruits[0] ); // Apple -alert( fruits[1] ); // Orange -alert( fruits[2] ); // Plum - -// how many elements (last index + 1) -alert( fruits.length ); // 3 -``` - -Please note that arrays do not form a separate language type. They are based on objects. But they greatly extend them with features of their own, methods to add, remove, extract elements from the array, to sort arrays and more. We'll cover them in the chapter . - -## Symbol type - -The `symbol` type is used in conjunction with objects. Probably we won't need them soon, but it's the 7th and the last type of the language, so we must mention it here for the sake of completeness. - -A "symbol" represents an unique identifier with a given name. - -A value of this type can be created using `Symbol(name)`: - -```js -// id is a symbol with the name "id" -let id = Symbol("id"); -``` - -Symbols in JavaScript are different from symbols in Ruby language (if you are familiar with it, please don't get trapped by the same word). Two symbols with the same name are not the same: - -```js run -let id1 = Symbol("id"); -let id2 = Symbol("id"); - -*!* -alert(id1 == id2); // false -*/!* -``` - -Symbols is a special primitive type used for identifiers, which are guaranteed to be unique. So, even if we create many symbols with the same name, they are still unique. - -The use case for symbols is to create "concealed" properties of an object, that no other part of code can occasionally access or overwrite. - -For instance, if we want to store an "identifier" for the object `user`, we can create a symbol with the name `id` for it: - -```js run -let user = { name: "John" }; -let id = Symbol("id"); - -user[id] = "ID Value"; -alert( user[id] ); // we can access the data using the symbol as the key -``` - -Now let's imagine that another script wants to have his own "id" property inside `user`, for his own purposes. That may be another javascript library, so the scripts are completely unaware for each other. - -No problem. It can create its own `Symbol("id")`. There will be no conflict, because symbols are always different, even if they have the same name. - -Please note if we used a string `"id"` instead of a symbol for the same purpose, then there could be a conflict: - -```js run -let user = { name: "John" }; - -// our script -user.id = "ID Value"; - -// ...if later another script the uses same name for its purposes... - -user.id = "ID 2" -// then boom! overwritten! it did not mean to harm the colleague, but did it! -``` - -Two `Symbol("id")` are not equal, that's why they would allow to store values safely. - - -Symbols are widely used by the JavaScript language itself to store "system" properties which we'll learn in later chapters. - -## The typeof operator [#type-typeof] - -The `typeof` operator returns the type of the argument. It's useful when we want to process values of different types differently, or just want to make a quick check. - -It supports two forms of syntax: - -1. As an operator: `typeof x`. -2. Function style: `typeof(x)`. - -In other words, it works both with the brackets or without them. The result is the same. - -The call to `typeof x` returns a string, which has the type name: - -```js -typeof undefined // "undefined" - -typeof 0 // "number" - -typeof true // "boolean" - -typeof "foo" // "string" - -typeof Symbol("id") // "symbol" - -typeof {} // "object" - -*!* -typeof [] // "object" (1) -*/!* - -*!* -typeof null // "object" (2) -*/!* - -*!* -typeof alert // "function" (3) -*/!* -``` - -The last three lines may be a little unobvious so here's explanations: - -1. The array is not a type of its own, it is based on object, that's why `typeof []` is `"object"`. -2. The result of `typeof null` equals to `"object"`. That's wrong. It is an officially recognized error in `typeof`, kept for compatibility. Of course, `null` is not an object. It is a special value with a separate type of its own. So, again, that's an error in the language. -3. The result of `typeof alert` is `"function"`, because `alert` is a function of the language. We'll study functions in the near future and see that actually functions belong to the object type. But `typeof` treats them differently. That's very convenient in practice. - - - -## Summary - -There are 7 basic types in JavaScript. - -- `number` for numbers of any kind, can convert into it using `Number(value)`. -- `string` for strings and characters, can convert into it using `String(value)`. -- `boolean` for `true`/`false`, can convert into it using `Boolean(value)`. -- `null` for unknown values. -- `undefined` for unassigned values. -- `symbol` for unique identifiers. -- `object` for more complex data structures. - -The `typeof` operator allows to see which type is stored in the variable. - diff --git a/1-js/2-first-steps/07-types/object-user-delete.png b/1-js/2-first-steps/07-types/object-user-delete.png deleted file mode 100644 index 3022fef2..00000000 Binary files a/1-js/2-first-steps/07-types/object-user-delete.png and /dev/null differ diff --git a/1-js/2-first-steps/07-types/object-user-delete@2x.png b/1-js/2-first-steps/07-types/object-user-delete@2x.png deleted file mode 100644 index 3a17a1e4..00000000 Binary files a/1-js/2-first-steps/07-types/object-user-delete@2x.png and /dev/null differ diff --git a/1-js/2-first-steps/07-types/object-user-isadmin.png b/1-js/2-first-steps/07-types/object-user-isadmin.png deleted file mode 100644 index e0f3bcb6..00000000 Binary files a/1-js/2-first-steps/07-types/object-user-isadmin.png and /dev/null differ diff --git a/1-js/2-first-steps/07-types/object-user-isadmin@2x.png b/1-js/2-first-steps/07-types/object-user-isadmin@2x.png deleted file mode 100644 index 79dc9a5b..00000000 Binary files a/1-js/2-first-steps/07-types/object-user-isadmin@2x.png and /dev/null differ diff --git a/1-js/2-first-steps/07-types/object-user.png b/1-js/2-first-steps/07-types/object-user.png deleted file mode 100644 index 2d4023e1..00000000 Binary files a/1-js/2-first-steps/07-types/object-user.png and /dev/null differ diff --git a/1-js/2-first-steps/07-types/object-user@2x.png b/1-js/2-first-steps/07-types/object-user@2x.png deleted file mode 100644 index a3ce20ed..00000000 Binary files a/1-js/2-first-steps/07-types/object-user@2x.png and /dev/null differ diff --git a/1-js/2-first-steps/08-type-conversions/object-user-delete.png b/1-js/2-first-steps/08-type-conversions/object-user-delete.png deleted file mode 100644 index 3022fef2..00000000 Binary files a/1-js/2-first-steps/08-type-conversions/object-user-delete.png and /dev/null differ diff --git a/1-js/2-first-steps/08-type-conversions/object-user-delete@2x.png b/1-js/2-first-steps/08-type-conversions/object-user-delete@2x.png deleted file mode 100644 index 3a17a1e4..00000000 Binary files a/1-js/2-first-steps/08-type-conversions/object-user-delete@2x.png and /dev/null differ diff --git a/1-js/2-first-steps/08-type-conversions/object-user-isadmin.png b/1-js/2-first-steps/08-type-conversions/object-user-isadmin.png deleted file mode 100644 index e0f3bcb6..00000000 Binary files a/1-js/2-first-steps/08-type-conversions/object-user-isadmin.png and /dev/null differ diff --git a/1-js/2-first-steps/08-type-conversions/object-user-isadmin@2x.png b/1-js/2-first-steps/08-type-conversions/object-user-isadmin@2x.png deleted file mode 100644 index 79dc9a5b..00000000 Binary files a/1-js/2-first-steps/08-type-conversions/object-user-isadmin@2x.png and /dev/null differ diff --git a/1-js/2-first-steps/08-type-conversions/object-user.png b/1-js/2-first-steps/08-type-conversions/object-user.png deleted file mode 100644 index 2d4023e1..00000000 Binary files a/1-js/2-first-steps/08-type-conversions/object-user.png and /dev/null differ diff --git a/1-js/2-first-steps/08-type-conversions/object-user@2x.png b/1-js/2-first-steps/08-type-conversions/object-user@2x.png deleted file mode 100644 index a3ce20ed..00000000 Binary files a/1-js/2-first-steps/08-type-conversions/object-user@2x.png and /dev/null differ diff --git a/1-js/2-first-steps/13-ifelse/1-if-zero-string/solution.md b/1-js/2-first-steps/10-ifelse/1-if-zero-string/solution.md similarity index 100% rename from 1-js/2-first-steps/13-ifelse/1-if-zero-string/solution.md rename to 1-js/2-first-steps/10-ifelse/1-if-zero-string/solution.md diff --git a/1-js/2-first-steps/13-ifelse/1-if-zero-string/task.md b/1-js/2-first-steps/10-ifelse/1-if-zero-string/task.md similarity index 100% rename from 1-js/2-first-steps/13-ifelse/1-if-zero-string/task.md rename to 1-js/2-first-steps/10-ifelse/1-if-zero-string/task.md diff --git a/1-js/2-first-steps/13-ifelse/2-check-standard/ifelse_task2.png b/1-js/2-first-steps/10-ifelse/2-check-standard/ifelse_task2.png similarity index 100% rename from 1-js/2-first-steps/13-ifelse/2-check-standard/ifelse_task2.png rename to 1-js/2-first-steps/10-ifelse/2-check-standard/ifelse_task2.png diff --git a/1-js/2-first-steps/13-ifelse/2-check-standard/ifelse_task2/index.html b/1-js/2-first-steps/10-ifelse/2-check-standard/ifelse_task2/index.html similarity index 100% rename from 1-js/2-first-steps/13-ifelse/2-check-standard/ifelse_task2/index.html rename to 1-js/2-first-steps/10-ifelse/2-check-standard/ifelse_task2/index.html diff --git a/1-js/2-first-steps/13-ifelse/2-check-standard/ifelse_task2@2x.png b/1-js/2-first-steps/10-ifelse/2-check-standard/ifelse_task2@2x.png similarity index 100% rename from 1-js/2-first-steps/13-ifelse/2-check-standard/ifelse_task2@2x.png rename to 1-js/2-first-steps/10-ifelse/2-check-standard/ifelse_task2@2x.png diff --git a/1-js/2-first-steps/13-ifelse/2-check-standard/solution.md b/1-js/2-first-steps/10-ifelse/2-check-standard/solution.md similarity index 100% rename from 1-js/2-first-steps/13-ifelse/2-check-standard/solution.md rename to 1-js/2-first-steps/10-ifelse/2-check-standard/solution.md diff --git a/1-js/2-first-steps/13-ifelse/2-check-standard/task.md b/1-js/2-first-steps/10-ifelse/2-check-standard/task.md similarity index 100% rename from 1-js/2-first-steps/13-ifelse/2-check-standard/task.md rename to 1-js/2-first-steps/10-ifelse/2-check-standard/task.md diff --git a/1-js/2-first-steps/13-ifelse/3-sign/if_sign/index.html b/1-js/2-first-steps/10-ifelse/3-sign/if_sign/index.html similarity index 100% rename from 1-js/2-first-steps/13-ifelse/3-sign/if_sign/index.html rename to 1-js/2-first-steps/10-ifelse/3-sign/if_sign/index.html diff --git a/1-js/2-first-steps/13-ifelse/3-sign/solution.md b/1-js/2-first-steps/10-ifelse/3-sign/solution.md similarity index 100% rename from 1-js/2-first-steps/13-ifelse/3-sign/solution.md rename to 1-js/2-first-steps/10-ifelse/3-sign/solution.md diff --git a/1-js/2-first-steps/13-ifelse/3-sign/task.md b/1-js/2-first-steps/10-ifelse/3-sign/task.md similarity index 100% rename from 1-js/2-first-steps/13-ifelse/3-sign/task.md rename to 1-js/2-first-steps/10-ifelse/3-sign/task.md diff --git a/1-js/2-first-steps/13-ifelse/4-check-login/ifelse_task.png b/1-js/2-first-steps/10-ifelse/4-check-login/ifelse_task.png similarity index 100% rename from 1-js/2-first-steps/13-ifelse/4-check-login/ifelse_task.png rename to 1-js/2-first-steps/10-ifelse/4-check-login/ifelse_task.png diff --git a/1-js/2-first-steps/13-ifelse/4-check-login/ifelse_task@2x.png b/1-js/2-first-steps/10-ifelse/4-check-login/ifelse_task@2x.png similarity index 100% rename from 1-js/2-first-steps/13-ifelse/4-check-login/ifelse_task@2x.png rename to 1-js/2-first-steps/10-ifelse/4-check-login/ifelse_task@2x.png diff --git a/1-js/2-first-steps/13-ifelse/4-check-login/solution.md b/1-js/2-first-steps/10-ifelse/4-check-login/solution.md similarity index 100% rename from 1-js/2-first-steps/13-ifelse/4-check-login/solution.md rename to 1-js/2-first-steps/10-ifelse/4-check-login/solution.md diff --git a/1-js/2-first-steps/13-ifelse/4-check-login/task.md b/1-js/2-first-steps/10-ifelse/4-check-login/task.md similarity index 100% rename from 1-js/2-first-steps/13-ifelse/4-check-login/task.md rename to 1-js/2-first-steps/10-ifelse/4-check-login/task.md diff --git a/1-js/2-first-steps/13-ifelse/5-rewrite-if-question/solution.md b/1-js/2-first-steps/10-ifelse/5-rewrite-if-question/solution.md similarity index 100% rename from 1-js/2-first-steps/13-ifelse/5-rewrite-if-question/solution.md rename to 1-js/2-first-steps/10-ifelse/5-rewrite-if-question/solution.md diff --git a/1-js/2-first-steps/13-ifelse/5-rewrite-if-question/task.md b/1-js/2-first-steps/10-ifelse/5-rewrite-if-question/task.md similarity index 100% rename from 1-js/2-first-steps/13-ifelse/5-rewrite-if-question/task.md rename to 1-js/2-first-steps/10-ifelse/5-rewrite-if-question/task.md diff --git a/1-js/2-first-steps/13-ifelse/6-rewrite-if-else-question/solution.md b/1-js/2-first-steps/10-ifelse/6-rewrite-if-else-question/solution.md similarity index 100% rename from 1-js/2-first-steps/13-ifelse/6-rewrite-if-else-question/solution.md rename to 1-js/2-first-steps/10-ifelse/6-rewrite-if-else-question/solution.md diff --git a/1-js/2-first-steps/13-ifelse/6-rewrite-if-else-question/task.md b/1-js/2-first-steps/10-ifelse/6-rewrite-if-else-question/task.md similarity index 100% rename from 1-js/2-first-steps/13-ifelse/6-rewrite-if-else-question/task.md rename to 1-js/2-first-steps/10-ifelse/6-rewrite-if-else-question/task.md diff --git a/1-js/2-first-steps/13-ifelse/article.md b/1-js/2-first-steps/10-ifelse/article.md similarity index 100% rename from 1-js/2-first-steps/13-ifelse/article.md rename to 1-js/2-first-steps/10-ifelse/article.md diff --git a/1-js/2-first-steps/14-logical-ops/1-alert-null-2-undefined/solution.md b/1-js/2-first-steps/11-logical-ops/1-alert-null-2-undefined/solution.md similarity index 100% rename from 1-js/2-first-steps/14-logical-ops/1-alert-null-2-undefined/solution.md rename to 1-js/2-first-steps/11-logical-ops/1-alert-null-2-undefined/solution.md diff --git a/1-js/2-first-steps/14-logical-ops/1-alert-null-2-undefined/task.md b/1-js/2-first-steps/11-logical-ops/1-alert-null-2-undefined/task.md similarity index 100% rename from 1-js/2-first-steps/14-logical-ops/1-alert-null-2-undefined/task.md rename to 1-js/2-first-steps/11-logical-ops/1-alert-null-2-undefined/task.md diff --git a/1-js/2-first-steps/14-logical-ops/2-alert-or/solution.md b/1-js/2-first-steps/11-logical-ops/2-alert-or/solution.md similarity index 100% rename from 1-js/2-first-steps/14-logical-ops/2-alert-or/solution.md rename to 1-js/2-first-steps/11-logical-ops/2-alert-or/solution.md diff --git a/1-js/2-first-steps/14-logical-ops/2-alert-or/task.md b/1-js/2-first-steps/11-logical-ops/2-alert-or/task.md similarity index 100% rename from 1-js/2-first-steps/14-logical-ops/2-alert-or/task.md rename to 1-js/2-first-steps/11-logical-ops/2-alert-or/task.md diff --git a/1-js/2-first-steps/14-logical-ops/3-alert-1-null-2/solution.md b/1-js/2-first-steps/11-logical-ops/3-alert-1-null-2/solution.md similarity index 100% rename from 1-js/2-first-steps/14-logical-ops/3-alert-1-null-2/solution.md rename to 1-js/2-first-steps/11-logical-ops/3-alert-1-null-2/solution.md diff --git a/1-js/2-first-steps/14-logical-ops/3-alert-1-null-2/task.md b/1-js/2-first-steps/11-logical-ops/3-alert-1-null-2/task.md similarity index 100% rename from 1-js/2-first-steps/14-logical-ops/3-alert-1-null-2/task.md rename to 1-js/2-first-steps/11-logical-ops/3-alert-1-null-2/task.md diff --git a/1-js/2-first-steps/14-logical-ops/4-alert-and/solution.md b/1-js/2-first-steps/11-logical-ops/4-alert-and/solution.md similarity index 100% rename from 1-js/2-first-steps/14-logical-ops/4-alert-and/solution.md rename to 1-js/2-first-steps/11-logical-ops/4-alert-and/solution.md diff --git a/1-js/2-first-steps/14-logical-ops/4-alert-and/task.md b/1-js/2-first-steps/11-logical-ops/4-alert-and/task.md similarity index 100% rename from 1-js/2-first-steps/14-logical-ops/4-alert-and/task.md rename to 1-js/2-first-steps/11-logical-ops/4-alert-and/task.md diff --git a/1-js/2-first-steps/14-logical-ops/5-alert-and-or/solution.md b/1-js/2-first-steps/11-logical-ops/5-alert-and-or/solution.md similarity index 100% rename from 1-js/2-first-steps/14-logical-ops/5-alert-and-or/solution.md rename to 1-js/2-first-steps/11-logical-ops/5-alert-and-or/solution.md diff --git a/1-js/2-first-steps/14-logical-ops/5-alert-and-or/task.md b/1-js/2-first-steps/11-logical-ops/5-alert-and-or/task.md similarity index 100% rename from 1-js/2-first-steps/14-logical-ops/5-alert-and-or/task.md rename to 1-js/2-first-steps/11-logical-ops/5-alert-and-or/task.md diff --git a/1-js/2-first-steps/14-logical-ops/6-check-if-in-range/solution.md b/1-js/2-first-steps/11-logical-ops/6-check-if-in-range/solution.md similarity index 100% rename from 1-js/2-first-steps/14-logical-ops/6-check-if-in-range/solution.md rename to 1-js/2-first-steps/11-logical-ops/6-check-if-in-range/solution.md diff --git a/1-js/2-first-steps/14-logical-ops/6-check-if-in-range/task.md b/1-js/2-first-steps/11-logical-ops/6-check-if-in-range/task.md similarity index 100% rename from 1-js/2-first-steps/14-logical-ops/6-check-if-in-range/task.md rename to 1-js/2-first-steps/11-logical-ops/6-check-if-in-range/task.md diff --git a/1-js/2-first-steps/14-logical-ops/7-check-if-out-range/solution.md b/1-js/2-first-steps/11-logical-ops/7-check-if-out-range/solution.md similarity index 100% rename from 1-js/2-first-steps/14-logical-ops/7-check-if-out-range/solution.md rename to 1-js/2-first-steps/11-logical-ops/7-check-if-out-range/solution.md diff --git a/1-js/2-first-steps/14-logical-ops/7-check-if-out-range/task.md b/1-js/2-first-steps/11-logical-ops/7-check-if-out-range/task.md similarity index 100% rename from 1-js/2-first-steps/14-logical-ops/7-check-if-out-range/task.md rename to 1-js/2-first-steps/11-logical-ops/7-check-if-out-range/task.md diff --git a/1-js/2-first-steps/14-logical-ops/8-if-question/solution.md b/1-js/2-first-steps/11-logical-ops/8-if-question/solution.md similarity index 100% rename from 1-js/2-first-steps/14-logical-ops/8-if-question/solution.md rename to 1-js/2-first-steps/11-logical-ops/8-if-question/solution.md diff --git a/1-js/2-first-steps/14-logical-ops/8-if-question/task.md b/1-js/2-first-steps/11-logical-ops/8-if-question/task.md similarity index 100% rename from 1-js/2-first-steps/14-logical-ops/8-if-question/task.md rename to 1-js/2-first-steps/11-logical-ops/8-if-question/task.md diff --git a/1-js/2-first-steps/14-logical-ops/article.md b/1-js/2-first-steps/11-logical-ops/article.md similarity index 100% rename from 1-js/2-first-steps/14-logical-ops/article.md rename to 1-js/2-first-steps/11-logical-ops/article.md diff --git a/1-js/2-first-steps/15-while-for/1-loop-last-value/solution.md b/1-js/2-first-steps/12-while-for/1-loop-last-value/solution.md similarity index 100% rename from 1-js/2-first-steps/15-while-for/1-loop-last-value/solution.md rename to 1-js/2-first-steps/12-while-for/1-loop-last-value/solution.md diff --git a/1-js/2-first-steps/15-while-for/1-loop-last-value/task.md b/1-js/2-first-steps/12-while-for/1-loop-last-value/task.md similarity index 100% rename from 1-js/2-first-steps/15-while-for/1-loop-last-value/task.md rename to 1-js/2-first-steps/12-while-for/1-loop-last-value/task.md diff --git a/1-js/2-first-steps/15-while-for/2-which-value-while/solution.md b/1-js/2-first-steps/12-while-for/2-which-value-while/solution.md similarity index 100% rename from 1-js/2-first-steps/15-while-for/2-which-value-while/solution.md rename to 1-js/2-first-steps/12-while-for/2-which-value-while/solution.md diff --git a/1-js/2-first-steps/15-while-for/2-which-value-while/task.md b/1-js/2-first-steps/12-while-for/2-which-value-while/task.md similarity index 100% rename from 1-js/2-first-steps/15-while-for/2-which-value-while/task.md rename to 1-js/2-first-steps/12-while-for/2-which-value-while/task.md diff --git a/1-js/2-first-steps/15-while-for/3-which-value-for/solution.md b/1-js/2-first-steps/12-while-for/3-which-value-for/solution.md similarity index 100% rename from 1-js/2-first-steps/15-while-for/3-which-value-for/solution.md rename to 1-js/2-first-steps/12-while-for/3-which-value-for/solution.md diff --git a/1-js/2-first-steps/15-while-for/3-which-value-for/task.md b/1-js/2-first-steps/12-while-for/3-which-value-for/task.md similarity index 100% rename from 1-js/2-first-steps/15-while-for/3-which-value-for/task.md rename to 1-js/2-first-steps/12-while-for/3-which-value-for/task.md diff --git a/1-js/2-first-steps/15-while-for/4-for-even/solution.md b/1-js/2-first-steps/12-while-for/4-for-even/solution.md similarity index 100% rename from 1-js/2-first-steps/15-while-for/4-for-even/solution.md rename to 1-js/2-first-steps/12-while-for/4-for-even/solution.md diff --git a/1-js/2-first-steps/15-while-for/4-for-even/task.md b/1-js/2-first-steps/12-while-for/4-for-even/task.md similarity index 100% rename from 1-js/2-first-steps/15-while-for/4-for-even/task.md rename to 1-js/2-first-steps/12-while-for/4-for-even/task.md diff --git a/1-js/2-first-steps/15-while-for/5-replace-for-while/solution.md b/1-js/2-first-steps/12-while-for/5-replace-for-while/solution.md similarity index 100% rename from 1-js/2-first-steps/15-while-for/5-replace-for-while/solution.md rename to 1-js/2-first-steps/12-while-for/5-replace-for-while/solution.md diff --git a/1-js/2-first-steps/15-while-for/5-replace-for-while/task.md b/1-js/2-first-steps/12-while-for/5-replace-for-while/task.md similarity index 100% rename from 1-js/2-first-steps/15-while-for/5-replace-for-while/task.md rename to 1-js/2-first-steps/12-while-for/5-replace-for-while/task.md diff --git a/1-js/2-first-steps/15-while-for/6-repeat-until-correct/solution.md b/1-js/2-first-steps/12-while-for/6-repeat-until-correct/solution.md similarity index 100% rename from 1-js/2-first-steps/15-while-for/6-repeat-until-correct/solution.md rename to 1-js/2-first-steps/12-while-for/6-repeat-until-correct/solution.md diff --git a/1-js/2-first-steps/15-while-for/6-repeat-until-correct/task.md b/1-js/2-first-steps/12-while-for/6-repeat-until-correct/task.md similarity index 100% rename from 1-js/2-first-steps/15-while-for/6-repeat-until-correct/task.md rename to 1-js/2-first-steps/12-while-for/6-repeat-until-correct/task.md diff --git a/1-js/2-first-steps/15-while-for/7-list-primes/solution.md b/1-js/2-first-steps/12-while-for/7-list-primes/solution.md similarity index 100% rename from 1-js/2-first-steps/15-while-for/7-list-primes/solution.md rename to 1-js/2-first-steps/12-while-for/7-list-primes/solution.md diff --git a/1-js/2-first-steps/15-while-for/7-list-primes/task.md b/1-js/2-first-steps/12-while-for/7-list-primes/task.md similarity index 100% rename from 1-js/2-first-steps/15-while-for/7-list-primes/task.md rename to 1-js/2-first-steps/12-while-for/7-list-primes/task.md diff --git a/1-js/2-first-steps/15-while-for/article.md b/1-js/2-first-steps/12-while-for/article.md similarity index 79% rename from 1-js/2-first-steps/15-while-for/article.md rename to 1-js/2-first-steps/12-while-for/article.md index f6ebf2b0..314683b9 100644 --- a/1-js/2-first-steps/15-while-for/article.md +++ b/1-js/2-first-steps/12-while-for/article.md @@ -349,95 +349,13 @@ label: for(...) The call to a `break/continue` is only possible from inside the loop, and the label must be somewhere upwards from the directive. ```` -## The "for..in" loop - -To walk over all keys of an object, there exists a special form of the loop: `for..in`. This is a completely different thing from the `for(;;)` construct that we've studied before. - -The syntax: - -```js -for(key in object) { - // executes the body for each key among object properties -} -``` - -For instance, let's output all properties of `user`: - -```js run -let user = { - name: "John", - age: 30, - isAdmin: true -}; - -for(let key in user) { - // keys - alert( key ); // name, age, 30 - // values for the keys - alert( user[key] ); // John, 30, true -} -``` - -Note that all "for" constructs allow to declare the looping variable inside the loop, like `key` here. We could use another variable name here instead of `key`, for instance, "prop" is also widely used for iterations. - - -## The "for..of" loop - -And the third (the last one) kind of the `for` loop. Again it has a totally different meaning from what we've seen before. - -This form iterates over arrays. - -Actually, we can do it with the `for(;;)` loop: - -```js run -let fruits = ["Apple", "Orange", "Plum"]; - -// iterates over all elements: -// i is the number of the current element -// fruits[i] is the value of the current element -for(let i = 0; i < fruits.length; i++) { - alert( fruits[i] ); // Apple, then Orange, then Plum -} -``` - -The "generic" `for(;;)` loop works well even in most outdated browsers. - -The `for..of` syntax is shorter: - -```js run -let fruits = ["Apple", "Orange", "Plum"]; - -// iterates over all elements: -// fruit is the value of the current element -for(let fruit of fruits) { - alert( fruit ); -} -``` - -The `for..of` doesn't give access to the number of the current element, just its value, but in most cases that's enough. - -````smart header="Iterables" -Later we'll learn the concept of *iterable* objects in Javascript. An iterable object must implement special functionality that allows to use `for..of` on it. - -There are many iterable objects. For instance, a string is iterable, `for..of` will list characters in the example: - -```js run -for(let char of "test") { - alert( char ); t, then e, then s, then t -} -``` -```` - - ## Summary -There are 5 types of loops in JavaScript: +We covered 3 types of loops: - `while` -- the condition is checked before each iteration. - `do..while` -- the condition is checked after each iteration. - `for(;;)` -- the condition is checked before each iteration, additional settings available. -- `for(key in obj)` -- to iterate over object properties. -- `for(item of array)` -- to iterate over array items. To make an "infinite" loop, usually the `while(true)` construct is used. Such a loop, just like any other, can be stopped with the `break` directive. @@ -445,5 +363,3 @@ If we don't want to do anything more on this iteration and would like to forward `Break/continue` support labels before the loop. A label is the only way for `break/continue` to escape the nesting and go to the outer loop. -To get an array of object property names, there is a method `Object.keys(obj)`. - diff --git a/1-js/2-first-steps/16-switch/1-rewrite-switch-if-else/solution.md b/1-js/2-first-steps/13-switch/1-rewrite-switch-if-else/solution.md similarity index 100% rename from 1-js/2-first-steps/16-switch/1-rewrite-switch-if-else/solution.md rename to 1-js/2-first-steps/13-switch/1-rewrite-switch-if-else/solution.md diff --git a/1-js/2-first-steps/16-switch/1-rewrite-switch-if-else/task.md b/1-js/2-first-steps/13-switch/1-rewrite-switch-if-else/task.md similarity index 100% rename from 1-js/2-first-steps/16-switch/1-rewrite-switch-if-else/task.md rename to 1-js/2-first-steps/13-switch/1-rewrite-switch-if-else/task.md diff --git a/1-js/2-first-steps/16-switch/2-rewrite-if-switch/solution.md b/1-js/2-first-steps/13-switch/2-rewrite-if-switch/solution.md similarity index 100% rename from 1-js/2-first-steps/16-switch/2-rewrite-if-switch/solution.md rename to 1-js/2-first-steps/13-switch/2-rewrite-if-switch/solution.md diff --git a/1-js/2-first-steps/16-switch/2-rewrite-if-switch/task.md b/1-js/2-first-steps/13-switch/2-rewrite-if-switch/task.md similarity index 100% rename from 1-js/2-first-steps/16-switch/2-rewrite-if-switch/task.md rename to 1-js/2-first-steps/13-switch/2-rewrite-if-switch/task.md diff --git a/1-js/2-first-steps/16-switch/article.md b/1-js/2-first-steps/13-switch/article.md similarity index 100% rename from 1-js/2-first-steps/16-switch/article.md rename to 1-js/2-first-steps/13-switch/article.md diff --git a/1-js/2-first-steps/17-function-basics/1-if-else-required/solution.md b/1-js/2-first-steps/14-function-basics/1-if-else-required/solution.md similarity index 100% rename from 1-js/2-first-steps/17-function-basics/1-if-else-required/solution.md rename to 1-js/2-first-steps/14-function-basics/1-if-else-required/solution.md diff --git a/1-js/2-first-steps/17-function-basics/1-if-else-required/task.md b/1-js/2-first-steps/14-function-basics/1-if-else-required/task.md similarity index 100% rename from 1-js/2-first-steps/17-function-basics/1-if-else-required/task.md rename to 1-js/2-first-steps/14-function-basics/1-if-else-required/task.md diff --git a/1-js/2-first-steps/17-function-basics/2-rewrite-function-question-or/solution.md b/1-js/2-first-steps/14-function-basics/2-rewrite-function-question-or/solution.md similarity index 100% rename from 1-js/2-first-steps/17-function-basics/2-rewrite-function-question-or/solution.md rename to 1-js/2-first-steps/14-function-basics/2-rewrite-function-question-or/solution.md diff --git a/1-js/2-first-steps/17-function-basics/2-rewrite-function-question-or/task.md b/1-js/2-first-steps/14-function-basics/2-rewrite-function-question-or/task.md similarity index 100% rename from 1-js/2-first-steps/17-function-basics/2-rewrite-function-question-or/task.md rename to 1-js/2-first-steps/14-function-basics/2-rewrite-function-question-or/task.md diff --git a/1-js/2-first-steps/17-function-basics/3-min/solution.md b/1-js/2-first-steps/14-function-basics/3-min/solution.md similarity index 100% rename from 1-js/2-first-steps/17-function-basics/3-min/solution.md rename to 1-js/2-first-steps/14-function-basics/3-min/solution.md diff --git a/1-js/2-first-steps/17-function-basics/3-min/task.md b/1-js/2-first-steps/14-function-basics/3-min/task.md similarity index 100% rename from 1-js/2-first-steps/17-function-basics/3-min/task.md rename to 1-js/2-first-steps/14-function-basics/3-min/task.md diff --git a/1-js/2-first-steps/17-function-basics/4-pow/solution.md b/1-js/2-first-steps/14-function-basics/4-pow/solution.md similarity index 100% rename from 1-js/2-first-steps/17-function-basics/4-pow/solution.md rename to 1-js/2-first-steps/14-function-basics/4-pow/solution.md diff --git a/1-js/2-first-steps/17-function-basics/4-pow/task.md b/1-js/2-first-steps/14-function-basics/4-pow/task.md similarity index 100% rename from 1-js/2-first-steps/17-function-basics/4-pow/task.md rename to 1-js/2-first-steps/14-function-basics/4-pow/task.md diff --git a/1-js/2-first-steps/17-function-basics/article.md b/1-js/2-first-steps/14-function-basics/article.md similarity index 86% rename from 1-js/2-first-steps/17-function-basics/article.md rename to 1-js/2-first-steps/14-function-basics/article.md index 9c8e51ab..76844d6d 100644 --- a/1-js/2-first-steps/17-function-basics/article.md +++ b/1-js/2-first-steps/14-function-basics/article.md @@ -176,6 +176,68 @@ showMessage(from, "Hello"); // *Ann*: Hello alert( from ); // Ann ``` +## Default values + +If a parameter is not provided, then its value becomes `undefined`. + +For instance, the aforementioned function `showMessage(from, text)` can be called with a single argument: + +```js +showMessage("Ann"); +``` + +That's not an error. Such call would output `"Ann: undefined"`, because `text === undefined`. + +If we want to track when the function is called with a single argument and use a "default" value in this case, then we can check if `text` is defined, like here: + +```js run +function showMessage(from, text) { +*!* + if (text === undefined) { + text = 'no text given'; + } +*/!* + + alert( from + ": " + text ); +} + +showMessage("Ann", "Hello!"); // Ann: Hello! +*!* +showMessage("Ann"); // Ann: no text given +*/!* +``` + +There are also other ways to supply "default values" for missing arguments: + +- Use operator `||`: + + ```js + function showMessage(from, text) { + text = text || 'no text given'; + ... + } + ``` + + This way is shorter, but the argument is considered missing even if it exists, but is falsy, like an empty line, `0` or `null`. + +- Specify the default value after `=`: + + ```js run + function showMessage(from, *!*text = 'no text given'*/!*) { + alert( from + ": " + text ); + } + + showMessage("Ann"); // Ann: no text given + ``` + + Here `'no text given'` is a string, but it can be a more complex expression, which is only evaluated and assigned if the parameter is missing. So, this is also possible: + + ```js run + function showMessage(from, text = anotherFunction()) { + // anotherFunction() runs if no text given + } + ``` + ## Returning a value A function can return a value back into the calling code as the result. diff --git a/1-js/2-first-steps/17-function-basics/function_basics.png b/1-js/2-first-steps/14-function-basics/function_basics.png similarity index 100% rename from 1-js/2-first-steps/17-function-basics/function_basics.png rename to 1-js/2-first-steps/14-function-basics/function_basics.png diff --git a/1-js/2-first-steps/17-function-basics/function_basics@2x.png b/1-js/2-first-steps/14-function-basics/function_basics@2x.png similarity index 100% rename from 1-js/2-first-steps/17-function-basics/function_basics@2x.png rename to 1-js/2-first-steps/14-function-basics/function_basics@2x.png diff --git a/1-js/2-first-steps/19-function-expressions-arrows/article.md b/1-js/2-first-steps/15-function-expressions-arrows/article.md similarity index 71% rename from 1-js/2-first-steps/19-function-expressions-arrows/article.md rename to 1-js/2-first-steps/15-function-expressions-arrows/article.md index 0eb3934d..a5f6afb2 100644 --- a/1-js/2-first-steps/19-function-expressions-arrows/article.md +++ b/1-js/2-first-steps/15-function-expressions-arrows/article.md @@ -1,8 +1,8 @@ # Function expressions and arrows -In JavaScript, a function is a value. +In Javascript a function is not a "magical language structure", but a special kind of value. -We can declare it as we did before: +The syntax that we've used before is called *Function Declaration*: ```js function sayHi() { @@ -10,9 +10,7 @@ function sayHi() { } ``` -This syntax is called a "Function Declaration". - -...But there is another way of creating a function: +There is another way of creating a function that is called *Function Expression*: ```js let sayHi = function() { @@ -20,12 +18,8 @@ let sayHi = function() { }; ``` -The latter syntax is called a "Function Expression". - The meaning of these code samples is the same: "create a function and put it into the variable `sayHi`". -Let's stress: a function is not a "magical language structure", but a kind of value. Both syntaxes mean the same: create a special "function" value and put it into the variable. - No matter, how the function is defined -- it's just a value, stored in the variable `sayHi`. We can even print out that value using `alert`: @@ -98,62 +92,12 @@ The answer is simple: ```` - -## Function is an object - -Every value in Javascript has the type. What type of value is a function? - -In Javascript, a function is an object. - -For example, all functions have property `name` (function name) and `length` (number of arguments): - -```js run -function sayHi() { - alert("Hi"); -} - -alert( sayHi.name ); // sayHi -alert( sayHi.length ); // 0 -``` - -We can add our own properties to it as well: - -```js run -function sayHi() { - alert("Hi"); - - *!* - // let's count how many times we run - sayHi.counter++; - */!* -} -sayHi.counter = 0; // initial value - -sayHi(); // Hi -sayHi(); // Hi - -alert( `Called ${sayHi.counter} times` ); // Called 2 times -``` - - -```warn header="A property is not a variable" -A property assigned to a function like `sayHi.counter = 0` does *not* define a local variable `counter` inside it. In other words, a property `sayHi.counter` and `let counter` inside the function (if we have it) are two unrelated things. - -We can treat a function as an object for convenience, store properties in it, that has no effect on its execution. -``` - -There are many well-known Javascript libraries that make a great use of custom function properties. - -They create a "main" function and attach many other "helper" functions to it. For instance, the [jquery](https://jquery.com) library creates a function named `$`. The [lodash](https://lodash.com) library creates a function `_`. And then adds `_.clone`, `_.keyBy` and other properties to (see the [docs](https://lodash.com/docs) when you want learn more about them). - -So, a function can do a useful job by itself and also carry a bunch of other functionality in properties. - ```smart header="A function is a value representing an \"action\"" Regular values like strings or numbers represent the *data*. A function can be perceived as an *action*. -We can copy it between variables and run when we want. We can even add properties to it if we wish. +We can pass it between variables and run when we want. ``` @@ -345,111 +289,6 @@ But if a Function Declaration does not fit for some reason (we've seen an exampl ``` -## Named Function Expression - -Now the feature that exists for a Function Expression, but not for Function Declaration, and hence may be a reason to use them. - -**We can specify an "internal" name for a Function Expression.** - -Compare these two variants: - -```js -let sayHi = function() { // (1) - alert('Hello'); -}; - -let sayHi = function *!*func*/!*() { // (2) - alert('Hello'); -}; -``` - -Both create a function and put it into the variable `sayHi`. And usually we don't specify anything in the `function()`, so the 1st variant works fine. - -Although the function can move to another variable. As we've seen it's easy to copy a function and maybe replace the previous value with something else: - -```js run -let sayHi = function() { - alert('Hello'); -}; - -// oh maybe that's better? -let oldSayHi = sayHi; // keep the old variant here -sayHi = function() { // replace with a newer one - alert("What's up dude?"); -}; - - -oldSayHi(); // Hello -sayHi(); // What's up dude? -``` - -The problem may occur if a function references *itself* from inside. It happens when the function wants to access its properties (`sayHi.counter` in the example above), or sometimes it wants to call itself one more time. - - -But if the function has moved, then the old name is not relevant any move! - - -Let's see: - -```js run -// create a function -let sayHi = function() { - sayHi.counter++; - alert('Hi ' + sayHi.counter); -}; -sayHi.counter = 0; - -// move it -let movedSayHi = sayHi; - -// overwrite the old name to make things more obvious -sayHi = null; - -*!* -movedSayHi(); // Error: Cannot read property 'counter' of null -*/!* -``` - -The optional `name` which we can put into `function name()` is exactly meant to solve this kind of problems. - -- It is only visible from inside the function. -- It always references the current function. - -Let's use it to fix the code: - -```js run -// now with the internal name "say" -*!* -let sayHi = function say() { - say.counter++; - alert('Hi ' + say.counter); // and use it everywhere inside -}; -*/!* -sayHi.counter = 0; - -let movedSayHi = sayHi; - -sayHi = null; - -movedSayHi(); // Hi 1 -movedSayHi(); // Hi 2 (works) - -alert(say); // Error (say is undefined, that's normal) -``` - -Please note that: - -- The name `say` references the current function no matter where it is. That's why it works. -- The name `say` exists only inside the function. The last line demonstrates that. - -So the outer code still uses `sayHi` (or `movedSayHi` later). It doesn't see `say`, actually it doesn't need to see it. The `say` is an "internal function name", how it calls itself privately. - -A Function Expression with a name is called *Named Function Expression*. - -The "internal name" feature described here is only available for Function Expressions, not to Function Declarations. For Function Declarations, the `function name()` behaves like `sayHi`, there's just no syntax possibility to add a one more "internal" name for them. - - - ## Arrow functions [#arrow-functions] Enough with the complexities for now. Let's relax with another syntax of functions that can make our code shorter. @@ -562,6 +401,8 @@ It is used in very specific cases, like when we receive the code from the server ## Summary +[todo review] + - Functions are values. They can be assigned, copied or declared in any place of the code. - If the function is declared as a separate statement, in the main code flow -- that's called a Function Declaration. - If the function is created as a part of an expression -- it's a Function Expression. diff --git a/1-js/2-first-steps/07-types/2-hello-object/solution.md b/1-js/2-first-steps/16-object/2-hello-object/solution.md similarity index 100% rename from 1-js/2-first-steps/07-types/2-hello-object/solution.md rename to 1-js/2-first-steps/16-object/2-hello-object/solution.md diff --git a/1-js/2-first-steps/07-types/2-hello-object/task.md b/1-js/2-first-steps/16-object/2-hello-object/task.md similarity index 100% rename from 1-js/2-first-steps/07-types/2-hello-object/task.md rename to 1-js/2-first-steps/16-object/2-hello-object/task.md diff --git a/1-js/2-first-steps/07-types/3-sum-object/solution.md b/1-js/2-first-steps/16-object/3-sum-object/solution.md similarity index 100% rename from 1-js/2-first-steps/07-types/3-sum-object/solution.md rename to 1-js/2-first-steps/16-object/3-sum-object/solution.md diff --git a/1-js/2-first-steps/07-types/3-sum-object/task.md b/1-js/2-first-steps/16-object/3-sum-object/task.md similarity index 100% rename from 1-js/2-first-steps/07-types/3-sum-object/task.md rename to 1-js/2-first-steps/16-object/3-sum-object/task.md diff --git a/1-js/2-first-steps/16-object/article.md b/1-js/2-first-steps/16-object/article.md new file mode 100644 index 00000000..ce71247c --- /dev/null +++ b/1-js/2-first-steps/16-object/article.md @@ -0,0 +1,691 @@ + +# Objects as dictionaries + +The `object` type is special. + +All other types are called "primitive", because their values can contain only a single thing (be it a string or a number or whatever). + +In contrast, objects are used to store *keyed collections* of various data and more complex entities. + +[cut] + +An object is defined with the figure brackets `{…}` with an optional list of "key: value" pairs. In programming that's sometimes called an "associative array" or a "hash". + +We can imagine an object as a cabinet with signed files. Every piece of data is stored in it's file by the key. It's easy to find a file by it's name or add/remove a file. + +![](object.png) + +An empty object ("empty cabinet") can be created using one of two syntaxes: + +```js +let user = new Object(); // "object constructor" syntax +let user = {}; // "object literal" syntax +``` + +![](object-user-empty.png) + +Usually, the figure brackets `{...}` are used. That declaration is called an *object literal*. + +## Literals and properties + +We can immediately put some data into `{...}` as "key: value" pairs. Every pair is called *an object property*: + +```js +let user = { // an object + name: "John", // by key "name" store value "John" + age: 30 // by key "age" store value 30 +}; +``` + +A property has an identifier (also "name" and "key") before the colon `":"` and a value to the right of it. + +In the `user` object, there are two properties: + +1. The first property has the name `"name"` and the value `"John"`. +2. The second one has the name `"age"` and the value `30`. + +The `user` object can be imagined as a cabinet with two signed files labelled "name" and "age". + +![user object](object-user.png) + +We can add, remove and read files from it any time. + +Property values are accessible using the dot notation: + +```js +// get fields of the object: +alert( user.name ); // John +alert( user.age ); // 30 +``` + +A value can be of any time, let's add a boolean one: + +```js +user.isAdmin = true; +``` + +![user object 2](object-user-isadmin.png) + +...And remove `age` with the help of `delete` operator: + +```js +delete user.age; +``` + +![user object 3](object-user-delete.png) + +We can also use multiword property names, but then they must be quoted: + +```js +let user = { + name: "John", + age: 30, + "likes birds": true // multiword property name must be quoted +}; +``` + +![](object-user-props.png) + +## Square brackets + +For multiword properties, the dot access won't work: + +```js +// this would give a syntax error +user.likes birds = true +``` + +That's because the dot requires the key to be a valid variable identifier. That is: no spaces and other limitations. + +There's an alternative "square bracket notation" that works with any string: + +```js +user["likes birds"] = true; +``` + +Square brackets are also the way to access a property by the name from the variable: + +```js +let key = "likes birds"; +user[key] = true; // same as above +``` + +The square brackets mean: "take the property name from the variable". + +The variable can be assigned at run-time, for instance: + +```js run +let user = { + name: "John", + age: 30 +}; + +let key = prompt("What do you want to know about the user?", "name"); + +// access by variable +alert( user[key] ); // John (if enter "name") +``` + +Square brackets also can be used in an object literal. + +That's called a *computed property*: + +```js run +let fruit = prompt("Which fruit to buy?", "apple"); + +let bag = { +*!* + [fruit]: 5, // the name of the property is taken from the variable fruit +*/!* +}; + +alert( bag.apple ); // 5 if fruit="apple" +``` + +Here, the object `bag` is created with a property with the name from `fruit` variable and the value `5`. + +Essentially, that works the same as: +```js +let bag = {}; +bag[fruit] = 5; +``` + +We could have used a more complex expression inside square brackets. Anything that results in a property name: + +```js +let fruit = 'apple'; +let bag = { + [ 'apple' + 'Computers' ]: 5 // bag.appleComputers = 5 +}; +``` + +Square brackets are much more powerful than the dot notation. They allow any property names and variables. But they are more cumbersome to write. So most of the time, when property names are known and simple, the dot is used. And if we need something more complex, then we can switch to square brackets. + + +## Property name shorthand + +In real code we quite often want to create an object with a property from a variable. + +For instance: + +```js run +function makeUser(name, age) { +*!* + // take values for name and age from variables +*/!* + return { + name: name, + age: age + }; +} + +let user = makeUser("John", 30); +alert(user.name); // John +``` + +There's a special shorthand notation that is shorter. + +Instead of `name:name` we can just write `name`, like this: + +```js +function makeUser(name, age) { +*!* + return { + name, // same as name: name + age // same as age: age + }; +*/!* +} +``` + +We can use both normal properties and shorthands in the same object: + +```js +let user = { + name, // same as name:name + age: 30 +}; +``` + + +````smart header="Trailing comma" +The last property may end with a comma: +```js +let user = { + name: "John", + age: 30*!*,*/!* +} +``` +That is called a "trailing" or "hanging" comma. Makes it easier to add/move/remove properties, because all lines become alike. +```` + + +````smart header="Reserved words are allowed as property names" +A variable cannot have a name equal to one of language-reserved words like "for", "let", "return" etc. + +But for an object property, there's no such restruction. Any name is fine: + +```js run +let obj = { + for: 1, + let: 2, + return: 3 +} + +alert( obj.for + obj.let + obj.return ); // 6 +``` + +Basically, any name is allowed, with one exclusion: `__proto__`. + +The built-in property named `__proto__` has a special functionality (we'll cover it later), and it can't be set to a non-object value: + +```js run +let obj = {}; +obj.__proto__ = 5; +alert(obj.__proto__); // [object Object], didn't work as intended +``` + +As you we see from the code, an assignment to a primitive is ignored. If we want to store *arbitrary* (user-provided) keys, then such behavior can be the source of bugs and even vulnerabilities, because it's unexpected. There's another data structure [Map](info:map-set-weakmap-weakset), that we'll learn in the chapter , which supports arbitrary keys. +```` + + + + +## Existance check + +A notable objects feature is that it's possible to access any property. There will be no error if the property doesn't exist! Accessing a non-existing property just returns `undefined`. It provides a very common way to test whether the property exists -- to get it and compare vs undefined: + +```js run +let user = {}; + +alert( user.noSuchProperty === undefined ); // true means "no such property" +``` + +There also exists a special operator `"in"` to check for the existance of a property. + +The syntax is: +```js +"key" in object +``` + +For instance: + +```js run +let user = { name: "John", age: 30 }; + +alert( "age" in user ); // true, user.age exists +alert( "blabla" in user ); // false, user.blabla doesn't exist +``` + +Please note that at the left side of `in` there must be a *property name*. That's usually a quoted string. + +If we omit quotes, that would mean a variable containing the actual name to be tested. For instance: + +```js run +let user = { age: 30 }; + +let key = "age"; +alert( *!*key*/!* in user ); // true, takes the name from key and checks for such property +``` + +````smart header="Using \"in\" for properties that store `undefined`" +Usually, the strict comparison `"=== undefined"` check works fine. But there's a special case when it fails, but `"in"` works correctly. + +It's when an object property exists, but stores `undefined`: + +```js run +let obj = { + test: undefined +}; + +alert( obj.test ); // it's undefined, so - no such property? + +alert( "test" in obj ); // true, the property does exist! +``` + + +In the code above, the property `obj.test` technically exists. So the `in` operator works right. + +Situations like this happen very rarely, because `undefined` is usually not assigned. We mostly use `null` for "unknown" or "empty" values. So the `in` operator is an exotic guest in the code. +```` + + +## The "for..in" loop + +To walk over all keys of an object, there exists a special form of the loop: `for..in`. This is a completely different thing from the `for(;;)` construct that we studied before. + +The syntax: + +```js +for(key in object) { + // executes the body for each key among object properties +} +``` + +For instance, let's output all properties of `user`: + +```js run +let user = { + name: "John", + age: 30, + isAdmin: true +}; + +for(let key in user) { + // keys + alert( key ); // name, age, 30 + // values for the keys + alert( user[key] ); // John, 30, true +} +``` + +Note that all "for" constructs allow to declare the looping variable inside the loop, like `let key` here. + +Also, we could use another variable name here instead of `key`. For instance, `"for(let prop in obj)"` is also widely used. + + +### Ordered like an object + +Are objects ordered? In other words, if we loop over an object, do we get all properties in the same order that they are added in it? + +The short answer is: "ordered like an object": integer properties are sorted, others appear in creation order. The details follow. + +As an example, let's consider an object with the phone codes: + +```js run +let codes = { + "49": "Germany", + "41": "Switzerland", + "44": "Great Britain", + // .., + "1": "USA" +}; + +*!* +for(let code in codes) { + alert(code); // 1, 41, 44, 49 +} +*/!* +``` + +The object may be used to suggest a list of options to the user. If we're making a site mainly for German audience then we probably want `49` to be the first. + +But if we run the code, we see a totally different picture: + +- USA (1) goes first +- then Switzerland (41) and so on. + +The phone codes go in the ascending sorted order, because they are integer. So we see `1, 41, 44, 49`. + +````smart header="Integer properties? What's that?" +The "integer property" term here means a string that can be converted to-from integer without a change. + +So, "49" is an integer property name, because when it's transformed to an integer number and back, it's still the same. But "+49" and "1.2" are not: + +```js run +alert( String(Math.trunc(Number("49"))) ); // "49", same, integer property +alert( String(Math.trunc(Number("+49"))) ); // "49", not same ⇒ not integer property +alert( String(Math.trunc(Number("1.2"))) ); // "1", not same ⇒ not integer property +``` +```` + +...On the other hand, if the keys are non-integer, then they are listed in the creation order, for instance: + +```js run +let user = { + name: "John", + surname: "Smith" +}; +user.age = 25; // add one more + +*!* +// non-integer properties are listed in the creation order +*/!* +for (let prop in user) { + alert( prop ); // name, surname, age +} +``` + +So, to fix the issue with the phone codes, we can "cheat" by making the codes non-integer. Adding a plus `"+"` sign before each code is enough. + +Like this: + +```js run +let codes = { + "+49": "Germany", + "+41": "Switzerland", + "+44": "Great Britain", + // .., + "+1": "USA" +}; + +for(let code in codes) { + alert( +code ); // 49, 41, 44, 1 +} +``` + +Now it works as intended. + + + +## References + +One of fundamental differences of objects vs primitives is that they are stored and copied "by reference". + +Primitive values: strings, numbers, booleans -- are assigned/copied "as a whole value". + +For instance: + +```js +let message = "Hello!"; +let phrase = message; +``` + +As a result we have two independant variables, each one is storing the string `"Hello!"`. + +![](variable-copy-value.png) + +Objects are not like that. + +**A variable stores not the object itself, but it's "address in memory", in other words "a reference" to it.** + +Here's the picture for the object: + +```js +let user = { + name: "John" +}; +``` + +![](variable-contains-reference.png) + +Note that the object itself is stored somewhere in memory. The variable `user` has a "reference" to it. + +**When an object variable is copied -- the reference is copied, the object is not duplicated.** + +If we imagine an object as a cabinet, then a variable is a key to it. Copying a variable duplicates the key, but not the cabinet itself. + +For instance: + +```js no-beautify +let user = { name: "John" }; + +let admin = user; // copy the reference +``` + +Now we have two variables, each one with the reference to the same object: + +![](variable-copy-reference.png) + +Now can use any variable to access the cabinet and modify its contents: + +```js run +let user = { name: 'John' }; + +let admin = user; + +*!* +admin.name = 'Pete'; // changed by the "admin" reference +*/!* + +alert(*!*user.name*/!*); // 'Pete', changes are seen from the "user" reference +``` + +The example above demonstrates that there is only one object. Like if we had a cabinet with two keys and used one of them (`admin`) to get into it -- later using the other one (`user`) we will see things modified. + + + +### Comparison by reference + +The equality `==` and strict equality `===` operators for objects work exactly the same, simple way. + +**Two object variables are equal only when reference the same object.** + +```js run +let a = {}; +let b = a; // copy the reference + +alert( a == b ); // true, both variables reference the same object +alert( a === b ); // true +``` + +In all other cases objects are non-equal, even if their content is the same. + +For instance: + +```js run +let a = {}; +let b = {}; // two independent objects + +alert( a == b ); // false +``` + +That rule only applies to object vs object equality checks. + +For other comparisons like whether an object less/greater than another object (`obj1 > obj2`) or for a comparison against a primitive `obj == 5`, objects are converted to primitives. We'll study how object conversions work very soon, but to say the truth, such comparisons occur very rarely in real code and usually are a result of a coding mistake. + +## Cloning and merging, Object.assign + +So, copying an object variable creates one more reference to the same object. + +But what if we need to duplicate an object? Create an independant copy, a clone? + +That's also doable, but a little bit more difficult, because there's no built-in method for that in Javascript. Actually, that's rarely needed, copying by reference is good most of the time. + +But if we really want that, then we need to create a new object and replicate the structure of the existing one by iterating over its properties and copying them on the primitive level. + +Like this: + +```js run +let user = { + name: "John", + age: 30 +}; + +*!* +let clone = {}; // the new empty object + +// let's copy all user properties into it +for (let key in user) { + clone[key] = user[key]; +} +*/!* + +// now clone is a fully independant clone +clone.name = "Pete"; // changed the data in it + +alert( user.name ); // still John +``` + +Also we can use the method [Object.assign](mdn:js/Object/assign) for that. + +The syntax is: + +```js +Object.assign(dest[, src1, src2, src3...]) +``` + +- `dest` and other arguments (can be as many as needed) are objects + +It copies the properties of all arguments starting from the 2nd (`src1`, `src2` etc) into the `dest`. Then it returns `dest`. + +For instance, we can use it to merge several objects into one: +```js +let user = { name: "John" }; + +let permissions1 = { canView: true }; +let permissions2 = { canEdit: true }; + +*!* +// copies all properties from permissions1 and permissions2 into user +Object.assign(user, permissions1, permissions2); +*/!* + +// now user = { name: "John", canView: true, canEdit: true } +``` + +If the receiving object (`user`) already has the same named property, it will be overwritten: + +```js +let user = { name: "John" }; + +// overwrite name, add isAdmin +Object.assign(user, { name: "Pete", isAdmin: true }); + +// now user = { name: "Pete", isAdmin: true } +``` + +We also can use `Object.assign` to replace the loop for simple cloning: + +```js +let user = { + name: "John", + age: 30 +}; + +*!* +let clone = Object.assign({}, user); +*/!* +``` + +It copies all properties of `user` into the empty object and returns it. Actually, the same as the loop, but shorter. + +Till now we assumed that all properties of `user` are primitive. But properties can be references to other objects. What to do with them? + +Like this: +```js run +let user = { + name: "John", + sizes: { + height: 182, + width: 50 + } +}; + +alert( user.sizes.height ); // 182 +``` + +Now it's not enough to copy `clone.sizes = user.sizes`, because the `user.sizes` is an object, it will be copied by reference. So `clone` and `user` will share the same sizes: + +Like this: +```js run +let user = { + name: "John", + sizes: { + height: 182, + width: 50 + } +}; + +let clone = Object.assign({}, user); + +alert( user.sizes === clone.sizes ); // true, same object + +user.sizes.width++; // change a property from one place +alert(clone.sizes.width); // 51, see the result from the other one +``` + +To fix that, we should use the cloning loop that examines each value of `user[key]` and, if it's an object, then replicate it's structure as well. That is called a "deep cloning". + +There's a standard algorithm for deep cloning that handles the case above and more complex cases, called the [Structured cloning algorithm](w3c.github.io/html/infrastructure.html#internal-structured-cloning-algorithm). Not to reinvent the wheel, we can use a working implementation of it from the Javascript library [lodash](https://lodash.com), the method is called [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep). + + + +## Summary + +[todo rewrite] + +Objects are associative arrays with several special features. + +- Property keys are either strings or symbols. +- Values can be of any type. + +Property access: + +- Read/write uses the dot notation: `obj.property` or square brackets `obj["property"]/obj[varWithKey]`. +- The deletion is made via the `delete` operator. +- Existance check is made by the comparison vs `undefined` or via the `in` operator. +- Three forms of looping: + - `for(key in obj)` for the keys. + - `for(value of Object.values(obj))` for the values. + - `for([key,value] of Object.entries(obj))` for both. + +- Ordering: + - Integer properties in sorted order first, then strings in creation order, then symbols in creation order. + - To keep the order for numeric properties, we can prepend them with `+` to make them look like non-numeric. + +- Objects are assigned and copied by reference. + +What we've just seen is called a "plain object", or just `Object`. + +There are many other kinds of objects in Javascript: + +- `Array` to store ordered data collections, +- `Date` to store the information about the date and time, +- `Error` to store the information about an error. +- ...And so on. + +Sometimes people say something like "Array type" or "Date type", but formally they are not types of their own, but belong to a single "object" data type. And they extend it in various ways. + +Objects in JavaScript are very powerful. Here we've just scratched the surface of the topic that is really huge. We'll be closely working with objects and learning more about them in further parts of the tutorial. + diff --git a/1-js/2-first-steps/16-object/object-user-delete.png b/1-js/2-first-steps/16-object/object-user-delete.png new file mode 100644 index 00000000..688158f9 Binary files /dev/null and b/1-js/2-first-steps/16-object/object-user-delete.png differ diff --git a/1-js/2-first-steps/16-object/object-user-delete@2x.png b/1-js/2-first-steps/16-object/object-user-delete@2x.png new file mode 100644 index 00000000..e1ef6554 Binary files /dev/null and b/1-js/2-first-steps/16-object/object-user-delete@2x.png differ diff --git a/1-js/4-data-structures/4-object/object-user-empty.png b/1-js/2-first-steps/16-object/object-user-empty.png similarity index 100% rename from 1-js/4-data-structures/4-object/object-user-empty.png rename to 1-js/2-first-steps/16-object/object-user-empty.png diff --git a/1-js/4-data-structures/4-object/object-user-empty@2x.png b/1-js/2-first-steps/16-object/object-user-empty@2x.png similarity index 100% rename from 1-js/4-data-structures/4-object/object-user-empty@2x.png rename to 1-js/2-first-steps/16-object/object-user-empty@2x.png diff --git a/1-js/2-first-steps/16-object/object-user-isadmin.png b/1-js/2-first-steps/16-object/object-user-isadmin.png new file mode 100644 index 00000000..4e76eeb7 Binary files /dev/null and b/1-js/2-first-steps/16-object/object-user-isadmin.png differ diff --git a/1-js/2-first-steps/16-object/object-user-isadmin@2x.png b/1-js/2-first-steps/16-object/object-user-isadmin@2x.png new file mode 100644 index 00000000..b4097769 Binary files /dev/null and b/1-js/2-first-steps/16-object/object-user-isadmin@2x.png differ diff --git a/1-js/4-data-structures/4-object/object-user-props.png b/1-js/2-first-steps/16-object/object-user-props.png similarity index 100% rename from 1-js/4-data-structures/4-object/object-user-props.png rename to 1-js/2-first-steps/16-object/object-user-props.png diff --git a/1-js/4-data-structures/4-object/object-user-props@2x.png b/1-js/2-first-steps/16-object/object-user-props@2x.png similarity index 100% rename from 1-js/4-data-structures/4-object/object-user-props@2x.png rename to 1-js/2-first-steps/16-object/object-user-props@2x.png diff --git a/1-js/2-first-steps/16-object/object-user.png b/1-js/2-first-steps/16-object/object-user.png new file mode 100644 index 00000000..16179209 Binary files /dev/null and b/1-js/2-first-steps/16-object/object-user.png differ diff --git a/1-js/2-first-steps/16-object/object-user@2x.png b/1-js/2-first-steps/16-object/object-user@2x.png new file mode 100644 index 00000000..72038953 Binary files /dev/null and b/1-js/2-first-steps/16-object/object-user@2x.png differ diff --git a/1-js/4-data-structures/4-object/object.png b/1-js/2-first-steps/16-object/object.png similarity index 100% rename from 1-js/4-data-structures/4-object/object.png rename to 1-js/2-first-steps/16-object/object.png diff --git a/1-js/4-data-structures/4-object/object@2x.png b/1-js/2-first-steps/16-object/object@2x.png similarity index 100% rename from 1-js/4-data-structures/4-object/object@2x.png rename to 1-js/2-first-steps/16-object/object@2x.png diff --git a/1-js/4-data-structures/4-object/variable-contains-reference.png b/1-js/2-first-steps/16-object/variable-contains-reference.png similarity index 100% rename from 1-js/4-data-structures/4-object/variable-contains-reference.png rename to 1-js/2-first-steps/16-object/variable-contains-reference.png diff --git a/1-js/4-data-structures/4-object/variable-contains-reference@2x.png b/1-js/2-first-steps/16-object/variable-contains-reference@2x.png similarity index 100% rename from 1-js/4-data-structures/4-object/variable-contains-reference@2x.png rename to 1-js/2-first-steps/16-object/variable-contains-reference@2x.png diff --git a/1-js/4-data-structures/4-object/variable-copy-reference.png b/1-js/2-first-steps/16-object/variable-copy-reference.png similarity index 100% rename from 1-js/4-data-structures/4-object/variable-copy-reference.png rename to 1-js/2-first-steps/16-object/variable-copy-reference.png diff --git a/1-js/4-data-structures/4-object/variable-copy-reference@2x.png b/1-js/2-first-steps/16-object/variable-copy-reference@2x.png similarity index 100% rename from 1-js/4-data-structures/4-object/variable-copy-reference@2x.png rename to 1-js/2-first-steps/16-object/variable-copy-reference@2x.png diff --git a/1-js/4-data-structures/4-object/variable-copy-value.png b/1-js/2-first-steps/16-object/variable-copy-value.png similarity index 100% rename from 1-js/4-data-structures/4-object/variable-copy-value.png rename to 1-js/2-first-steps/16-object/variable-copy-value.png diff --git a/1-js/4-data-structures/4-object/variable-copy-value@2x.png b/1-js/2-first-steps/16-object/variable-copy-value@2x.png similarity index 100% rename from 1-js/4-data-structures/4-object/variable-copy-value@2x.png rename to 1-js/2-first-steps/16-object/variable-copy-value@2x.png diff --git a/1-js/2-first-steps/20-object-methods/2-check-syntax/solution.md b/1-js/2-first-steps/17-object-methods/2-check-syntax/solution.md similarity index 100% rename from 1-js/2-first-steps/20-object-methods/2-check-syntax/solution.md rename to 1-js/2-first-steps/17-object-methods/2-check-syntax/solution.md diff --git a/1-js/2-first-steps/20-object-methods/2-check-syntax/task.md b/1-js/2-first-steps/17-object-methods/2-check-syntax/task.md similarity index 100% rename from 1-js/2-first-steps/20-object-methods/2-check-syntax/task.md rename to 1-js/2-first-steps/17-object-methods/2-check-syntax/task.md diff --git a/1-js/2-first-steps/20-object-methods/3-why-this/solution.md b/1-js/2-first-steps/17-object-methods/3-why-this/solution.md similarity index 100% rename from 1-js/2-first-steps/20-object-methods/3-why-this/solution.md rename to 1-js/2-first-steps/17-object-methods/3-why-this/solution.md diff --git a/1-js/2-first-steps/20-object-methods/3-why-this/task.md b/1-js/2-first-steps/17-object-methods/3-why-this/task.md similarity index 100% rename from 1-js/2-first-steps/20-object-methods/3-why-this/task.md rename to 1-js/2-first-steps/17-object-methods/3-why-this/task.md diff --git a/1-js/2-first-steps/20-object-methods/4-object-property-this/solution.md b/1-js/2-first-steps/17-object-methods/4-object-property-this/solution.md similarity index 100% rename from 1-js/2-first-steps/20-object-methods/4-object-property-this/solution.md rename to 1-js/2-first-steps/17-object-methods/4-object-property-this/solution.md diff --git a/1-js/2-first-steps/20-object-methods/4-object-property-this/task.md b/1-js/2-first-steps/17-object-methods/4-object-property-this/task.md similarity index 100% rename from 1-js/2-first-steps/20-object-methods/4-object-property-this/task.md rename to 1-js/2-first-steps/17-object-methods/4-object-property-this/task.md diff --git a/1-js/2-first-steps/20-object-methods/7-calculator/_js.view/solution.js b/1-js/2-first-steps/17-object-methods/7-calculator/_js.view/solution.js similarity index 100% rename from 1-js/2-first-steps/20-object-methods/7-calculator/_js.view/solution.js rename to 1-js/2-first-steps/17-object-methods/7-calculator/_js.view/solution.js diff --git a/1-js/2-first-steps/20-object-methods/7-calculator/_js.view/test.js b/1-js/2-first-steps/17-object-methods/7-calculator/_js.view/test.js similarity index 100% rename from 1-js/2-first-steps/20-object-methods/7-calculator/_js.view/test.js rename to 1-js/2-first-steps/17-object-methods/7-calculator/_js.view/test.js diff --git a/1-js/2-first-steps/20-object-methods/7-calculator/solution.md b/1-js/2-first-steps/17-object-methods/7-calculator/solution.md similarity index 100% rename from 1-js/2-first-steps/20-object-methods/7-calculator/solution.md rename to 1-js/2-first-steps/17-object-methods/7-calculator/solution.md diff --git a/1-js/2-first-steps/20-object-methods/7-calculator/task.md b/1-js/2-first-steps/17-object-methods/7-calculator/task.md similarity index 100% rename from 1-js/2-first-steps/20-object-methods/7-calculator/task.md rename to 1-js/2-first-steps/17-object-methods/7-calculator/task.md diff --git a/1-js/2-first-steps/20-object-methods/8-chain-calls/solution.md b/1-js/2-first-steps/17-object-methods/8-chain-calls/solution.md similarity index 100% rename from 1-js/2-first-steps/20-object-methods/8-chain-calls/solution.md rename to 1-js/2-first-steps/17-object-methods/8-chain-calls/solution.md diff --git a/1-js/2-first-steps/20-object-methods/8-chain-calls/task.md b/1-js/2-first-steps/17-object-methods/8-chain-calls/task.md similarity index 100% rename from 1-js/2-first-steps/20-object-methods/8-chain-calls/task.md rename to 1-js/2-first-steps/17-object-methods/8-chain-calls/task.md diff --git a/1-js/2-first-steps/20-object-methods/article.md b/1-js/2-first-steps/17-object-methods/article.md similarity index 69% rename from 1-js/2-first-steps/20-object-methods/article.md rename to 1-js/2-first-steps/17-object-methods/article.md index 228da9b8..10c9c32b 100644 --- a/1-js/2-first-steps/20-object-methods/article.md +++ b/1-js/2-first-steps/17-object-methods/article.md @@ -1,6 +1,6 @@ # Object methods, "this" -As we remember from the chapter , objects to store keyed collections of data. We usually create objects to represent entities of the real world, like users, orders and so on: +Objects are usually created to represent entities of the real world, like users, orders and so on: ```js let user = { @@ -11,7 +11,7 @@ let user = { And, in the real world, a user can `act`: to select something from the shopping cart, to login, to logout etc. -Let's implement the same in Javascript. +Let's implement the same in Javascript using functions in properties. [cut] @@ -43,12 +43,10 @@ So, here we've got a method `sayHi` of the object `user`. ```smart header="Object-oriented programming" When we write our code using objects to represent entities, that's called an [object-oriented programming](https://en.wikipedia.org/wiki/Object-oriented_programming), in short: "OOP". -OOP is a big thing, an interesting science of its own. How to choose the right entities? How to organize the code and the interaction between them? That's an architecture. - -We will make use of OOP further when we get enough familarity with basic functions of the language. +OOP is a big thing, an interesting science of its own. How to choose the right entities? How to organize the interaction between them? That's architecture. We will make use of OOP further when we get enough familarity with the language. ``` -Of course we could use a Function Declaration for the same purpose: +Of course, we could use a Function Declaration for the same purpose: ```js run let user = { @@ -66,11 +64,11 @@ user.sayHi = sayHi; user.sayHi(); // Hello! ``` -That would also work, but is longer. Also we get an "extra" function `sayHi` outside of the `user` object. Here we don't want it. +That would also work, but is longer. Also we get an "extra" function `sayHi` outside of the `user` object. Usually we don't want that. -## Method syntax +## Method shorthand -In an object literal, there's a shorter syntax for methods: +There exists a shorter syntax for methods in an object literal: ```js // these objects do the same @@ -81,6 +79,7 @@ let user = { } }; +// method shorthand looks better, right? let user = { *!* sayHi() { // same as "sayHi: function()" @@ -90,7 +89,7 @@ let user = { }; ``` -As demonstrated, we can omit a colon with the word `"function"`. And it actually looks better. +As demonstrated, we can omit a colon with the word `"function"`. To say the truth, the notations are not fully identical. There are subtle differences related to object inheritance (to be covered later), but for now they do not matter. In almost all cases the shorter syntax is preferred. @@ -98,7 +97,7 @@ To say the truth, the notations are not fully identical. There are subtle differ It's common that an object method needs to access the information stored in the object to do its job. -For instance, `user.sayHi()` may need to mention the name. +For instance, `user.sayHi()` may need to mention the name of the user. **To access the object, a method can use the `this` keyword.** @@ -158,7 +157,7 @@ user = null; // overwrite to make things obvious admin.sayHi(); // wops! inside sayHi(), the old name is used! error! ``` -The variant with `this.name` instead of `user.name` would work fine here. +If we used `this.name` instead of `user.name` inside the `alert`, then the code would work. ## "this" is free @@ -172,9 +171,9 @@ function sayHi() { } ``` -It is fully syntactically free. The function does not yet know what "this" value will be. It will be evaluated during the run-time. +It is fully syntactically free. The value of `this` will be evaluated during the run-time. -For instance, it may have different "this" when called in the context of different objects: +For instance, the function may have different "this" when called in contexts of different objects: ```js run let user = { name: "John" }; @@ -184,13 +183,16 @@ function sayHi() { alert( this.name ); } +// use the same functions in two objects user.f = sayHi; admin.g = sayHi; +// these calls have different this // "this" inside the function is the object "before the dot" -user.f(); // John -admin.g(); // Admin -admin['g'](); // Admin (dot or square brackets to access the method – doesn't matter) +user.f(); // John (this == user) +admin.g(); // Admin (this == admin) + +admin['g'](); // Admin (dot or square brackets access the method – doesn't matter) ``` Actually, we can call the function without an object at all: @@ -203,15 +205,11 @@ function sayHi() { sayHi(); ``` -In this case `this` is `undefined`. If we try to access `this.name`, there will be an error. +In this case `this` is `undefined` in strict mode. If we try to access `this.name`, there will be an error. -Such calls are often a result of the programming mistake. If a function has `this`, then it is usually to be called in the context of an object. +Please note that usually a call like this is not normal, but rather a programming mistake. If a function has `this`, then it is usually to be called in the context of an object. -```smart header="And without `use strict`..." -If you forget `use strict`, then you may see something like "window" in the example above. - -That's one of the odd things of the previous standard that `"use strict"` fixes. -``` +In a non-strict mode, if you forget `use strict` (let's hope you don't), then the value of `this` for a function without an object will be the *global object* (`"window"` for browser). We'll return to it later, but in a completely different chapter, because here it's just an odd thing of the previous standard that `"use strict"` fixes. ## Reference Type @@ -234,13 +232,15 @@ user.hi(); // John (the simple call works) On the last line the method `user.hi` is retrieved during the execution of the ternary `?`, and immediately called with brackets `()`. But that doesn't work right. You can see that the call results in an error, cause the value of `"this"` inside the call becomes `undefined`. +Actually, anything more complex than a simple `obj.method()` (or square brackets here) looses `this`. + If we want to understand why it happens -- the reason is in the details of how `obj.method()` call works. -The method call has two successive operations in it: +The method call is not a single thing. It has two successive operations in it: - the dot `'.'` retrieves the property - brackets `()` execute it (assuming that's a function). -So, you might have already asked yourself, why does it work? That is, if we put these operations on separate lines, then `this` is guaranted to be lost: +So, you might have already asked yourself, why does it work? That is, if we put these operations on separate lines, then `this` will be lost for sure: ```js run let user = { @@ -248,15 +248,18 @@ let user = { hi() { alert(this.name); } } +*!* +// split getting and calling the method in two lines let hi = user.hi; hi(); // Error, because this is undefined +*/!* ``` -...But for a single-line call `user.hi()` all is fine. +That's because a function is a value of its own. It does not carry the object. So `hi = user.hi` saves it into the variable, and then on the last line it is completely standalone. -That's because a function is a value of its own. It does not carry the object. So to pass it to the brackets, Javascript uses a trick -- the dot `'.'` returns not a function, but a value of the special [Reference Type](https://tc39.github.io/ecma262/#sec-reference-specification-type). +To make `user.hi()` calls work, Javascript uses a trick -- the dot `'.'` returns not a function, but a value of the special [Reference Type](https://tc39.github.io/ecma262/#sec-reference-specification-type). -The Reference Type is a "specification type". It does not exist in real, but is used internally. Engines are not required to implement it, just to make sure that code works as described. +The Reference Type is a "specification type". We can't explicitly access it, but it is used internally by the language. The value of the Reference Type is a combination `(base, name, strict)`, where: @@ -264,21 +267,18 @@ The value of the Reference Type is a combination `(base, name, strict)`, where: - `name` is the property. - `strict` is true if `use strict` is in effect. -The result of a property access `'.'` is a value of the Reference Type. For `user.sayHi` in strict mode it is: +The result of a property access `'.'` is a value of the Reference Type. For `user.hi` in strict mode it is: ```js // Reference Type value -(user, "sayHi", true) +(user, "hi", true) ``` -Then, when brackets `()` are called on the Reference Type, they receive the full information about the object and it's method, and can set the right `this = base`. +When brackets `()` are called on the Reference Type, they receive the full information about the object and it's method, and can set the right `this` (`=user` in this case). -Any other operation just gets `base[name]` value and uses it, discarding the reference type as a whole. +Any other operation like assignment `hi = user.hi` discards the reference type as a whole, takes the value of `user.hi` (a function) and passes it on. So any further operation "looses" `this`. -So any operation on the result of dot `'.'` except a direct call discards `this`. - - -That's why the value of `this` is only passed the right way if the function is called directly using a dot `obj.method()` or square brackets `obj[method]()` syntax (they do the same here). +So, as the result, the value of `this` is only passed the right way if the function is called directly using a dot `obj.method()` or square brackets `obj[method]()` syntax (they do the same here). ## Explicit "this" with "call/apply" [#call-apply] diff --git a/1-js/2-first-steps/18-function-parameters/article.md b/1-js/2-first-steps/18-function-parameters/article.md deleted file mode 100644 index 5f23fb18..00000000 --- a/1-js/2-first-steps/18-function-parameters/article.md +++ /dev/null @@ -1,303 +0,0 @@ -# Function parameters - -The syntax of function parameters is very versatile. - -It allows: - -- To specify values if the parameter if missing. -- To gather parameters into an array and deal with it instead of variables. -- To destructurize the object into parameters. -- And more. - -All these features aim to help us in writing good-looking and concise code. - -## Default values - -A function can be called with any number of arguments. If a parameter is not provided, but listed in the declaration, then its value becomes `undefined`. - -For instance, the aforementioned function `showMessage(from, text)` can be called with a single argument: - -```js -showMessage("Ann"); -``` - -That's not an error. Such call would output `"Ann: undefined"`, because `text === undefined`. - -If we want to track when the function is called with a single argument and use a "default" value in this case, then we can check if `text` is defined, like here: - -```js run -function showMessage(from, text) { -*!* - if (text === undefined) { - text = 'no text given'; - } -*/!* - - alert( from + ": " + text ); -} - -showMessage("Ann", "Hello!"); // Ann: Hello! -*!* -showMessage("Ann"); // Ann: no text given -*/!* -``` - -There are also other ways to supply "default values" for missing arguments: - -- Use operator `||`: - - ```js - function showMessage(from, text) { - text = text || 'no text given'; - ... - } - ``` - - This way is shorter, but the argument is considered missing even if it exists, but is falsy, like an empty line, `0` or `null`. - -- Specify the default value after `=`: - - ```js run - function showMessage(from, *!*text = 'no text given'*/!*) { - alert( from + ": " + text ); - } - - showMessage("Ann"); // Ann: no text given - ``` - - Here `'no text given'` is a string, but it can be a more complex expression, which is only evaluated and assigned if the parameter is missing. So, this is also possible: - - ```js run - function showMessage(from, text = anotherFunction()) { - // anotherFunction() is executed if no text given - } - ``` - -## Arbitrary number of arguments - -To support any number of arguments, we can use the rest operator `...`, similar to [destructuring](info:destructuring): - -```js run -function sumAll(...args) { - let sum = 0; - - for(let arg of args) sum += arg; - - return sum; -} - -alert( sumAll(1) ); // 1 -alert( sumAll(1, 2) ); // 3 -alert( sumAll(1, 2, 3) ); // 6 -``` - -We also can put few first arguments into variables and gather only the rest: - -```js run -function showName(firstName, lastName, ...rest) { - alert( firstName + ' ' + lastName ); // Julius Caesar - - // the rest = ["Consul", "of the Roman Republic"] - alert( rest[0] ); // Consul - alert( rest[1] ); // of the Roman Republic -} - -showName("Julius", "Caesar", "Consul", "of the Roman Republic"); -``` - -````warn header="The rest operator … must be at the end" -The rest operator `…` gathers all remaining arguments, so the following has no sense: - -```js -function f(arg1, ...rest, arg2) { // arg2 after ...rest ?! - // error -} -``` - -The `...rest` must always be the last. -```` - -````smart header="The `arguments` variable" - -In old times, there was no rest operator. But there is a special variable named `arguments` that contains all arguments by their index. It is still supported and can be used like this: - -```js run -function showName() { - alert( arguments[0] ); - alert( arguments[1] ); - alert( arguments.length ); - - // for..of works too - // for(let arg of arguments) alert(arg); -} - -// shows: Julius, Caesar, 2 -showName("Julius", "Caesar"); - -// shows: Ilya, undefined, 1 -showName("Ilya"); -``` - -The downside is that though `arguments` looks like an array, but it's not. It does not support many useful array methods that we'll study later, and if they're needed, then the rest operator should be used. -```` - -## Destructuring parameters - -There are times when a function may have many parameters, most of which are optional. That's especially true for user interfaces. Imagine a function that creates a menu. It may have a width, a height, a title, items list and so on. - -Here's a bad way to write such function: - -```js -function showMenu(title = "Untitled", width = 200, height = 100, items = []) { - // ... -} -``` - -The real-life problem is how to remember the order of arguments. Usually IDEs try to help us, especially if the code is well-documented, but still... Another problem is how to call a function when most parameters are ok by default. - -Like this? - -```js -showMenu("My Menu", undefined, undefined, ["Item1", "Item2"]) -``` - -That's ugly. And becomes unreadable when we deal with more parameters. - -Destructuring comes to the rescue! - -We can pass parameters as an object, and the function immediately destructurizes them into variables: - -```js run -let options = { - title: "My menu", - items: ["Item1", "Item2"] -}; - -*!* -function showMenu({title = "Untitled", width = 200, height = 100, items = []}) { -*/!* - alert( title + ' ' + width + ' ' + height ); // My Menu 100 200 - alert( items ); // Item1, Item2 -} - -showMenu(options); -``` - -We can also use the more complex destructuring with nestings and colon mappings: - -```js run -let options = { - title: "My menu", - items: ["Item1", "Item2"] -}; - -*!* -function showMenu({ - title = "Untitled", - width:w = 100, // width goes to w - height:h = 200, // height goes to h - items: [item1, item2] // items first element goes to item1, second to item2 -}) { -*/!* - alert( title + ' ' + w + ' ' + h ); // My Menu 100 200 - alert( item1 ); // Item1 - alert( item2 ); // Item2 -} - -showMenu(options); -``` - -The syntax is the same as for a destructuring assignment: -```js -function({ - incoming property: parameterName = defaultValue - ... -}) -``` - -Please note that such destructuring assumes that `showMenu()` does have an argument. If we want all values by default, then we should specify an empty object: - -```js -showMenu({}); - -// that would give an error -showMenu(); -``` - -We can fix this of course, by making `{}` a value by default for the whole destructuring thing: - - -```js run -// simplified parameters a bit for clarity -function showMenu(*!*{ title="Menu", width=100, height=200 } = {}*/!*) { - alert( title + ' ' + width + ' ' + height ); -} - -showMenu(); // Menu 100 200 -``` - -In the code above, the whole arguments object is `{}` by default, so there's always something to destructurize. - -## The spread operator [#spread-operator] - -As we've seen before, the rest operator `...` allows to gather parameters in the array. - -But there's a reverse named "the spread operator". It also looks like `...` and works at call-time. - -The spread operator allows to convert an array into a list of parameters, like this: - -```js run -let fullName = ["Gaius", "Julius", "Caesar"]; - -function showName(firstName, secondName, lastName) { - alert(firstName); - alert(secondName); - alert(lastName); -} - -// The spread operator ... passes an array as a list of arguments -showName(...fullName); -``` - -Let's see a more real-life example. - -There exist a built-in function [Math.max](mdn:js/Math/max) that takes a list of values and returns the greatest one: - -```js run -alert( Math.max(5, 7, -8, 1) ); // 7 -``` - -Imagine we have an array and want to select a maximum from it. Unfortunately, `Math.max` works with a list of parameters, not with arrays, so a direct call `Math.max(arr)` won't work. But we can use the spread operator `...` to pass the array as the list: - - -```js run -let arr = [5, 7, -8, 1]; - -alert( Math.max(...arr) ); // 7 -``` - -In short: -- When `...` occurs in function parameters, it's called a "rest operator" and gathers parameters into the array. -- When `...` occurs in a function call, it's called a "spread operator" and converts an array into the list. - -Together they help to travel between a list and an array of parameters with ease. - - -## Summary TODO - -[todo] -Основные улучшения в функциях: - -- Можно задавать параметры по умолчанию, а также использовать деструктуризацию для чтения приходящего объекта. -- Оператор spread (троеточие) в объявлении позволяет функции получать оставшиеся аргументы в массив: `function f(arg1, arg2, ...rest)`. -- Тот же оператор spread в вызове функции позволяет передать её массив как список аргументов (вместо `apply`). -- У функции есть свойство `name`, оно содержит имя, указанное при объявлении функции, либо, если его нет, то имя свойства или переменную, в которую она записана. Есть и некоторые другие ситуации, в которых интерпретатор подставляет "самое подходящее" имя. -- Объявление Function Declaration в блоке `{...}` видно только в этом блоке. -- Появились функции-стрелки: - - Без фигурных скобок возвращают выражение `expr`: `(args) => expr`. - - С фигурными скобками требуют явного `return`. - - Не имеют своих `this` и `arguments`, при обращении получают их из окружающего контекста. - - Не могут быть использованы как конструкторы, с `new`. - - - diff --git a/1-js/2-first-steps/22-primitives-methods/1-string-new-property/solution.md b/1-js/2-first-steps/18-primitives-methods/1-string-new-property/solution.md similarity index 100% rename from 1-js/2-first-steps/22-primitives-methods/1-string-new-property/solution.md rename to 1-js/2-first-steps/18-primitives-methods/1-string-new-property/solution.md diff --git a/1-js/2-first-steps/22-primitives-methods/1-string-new-property/task.md b/1-js/2-first-steps/18-primitives-methods/1-string-new-property/task.md similarity index 100% rename from 1-js/2-first-steps/22-primitives-methods/1-string-new-property/task.md rename to 1-js/2-first-steps/18-primitives-methods/1-string-new-property/task.md diff --git a/1-js/2-first-steps/22-primitives-methods/article.md b/1-js/2-first-steps/18-primitives-methods/article.md similarity index 73% rename from 1-js/2-first-steps/22-primitives-methods/article.md rename to 1-js/2-first-steps/18-primitives-methods/article.md index 3a382960..68beebf4 100644 --- a/1-js/2-first-steps/22-primitives-methods/article.md +++ b/1-js/2-first-steps/18-primitives-methods/article.md @@ -1,8 +1,8 @@ # Methods of primitives -In this section we'll see how JavaScript allows to work with primitives (strings, numbers etc) as if they were objects. They have methods and such. +JavaScript allows to work with primitives (strings, numbers etc) as if they were objects. They have methods and such. Of course, primitives are not objects (and here we plan to make it even more clear), but can be used like them. -Actually, most things in Javascript behave as objects. Of course primitives are not objects (and here we plan to make it even more clear), but can be used like them. +[cut] Let's formulate the definitive distinction between primitives and objects. @@ -32,18 +32,18 @@ There exist many built-in objects, including those that work with dates, errors, But features come at a price! -Objects are "heavier" than primitives. They require additional resources to support the internal property-managing machinery. But properties and methods are useful in programming, and engines try to optimize that, so the price is usually fair. +Objects are "heavier" than primitives. They require additional resources to support the internal machinery. But properties and methods are useful in programming, Javascript engines try to optimize them, so the price is usually fair. ## A primitive as an object Here's the paradox faced by the creator of JavaScript: -- There are many things one would want to do with a string or a number, could be great to access them as methods. -- Primitives must store a single value, be as fast and lightweight as possible. +- There are many things one would want to do with a primitive like a string or a number. Could be great to access them as methods. +- Primitives must be as fast and lightweight as possible. The solution looks a little bit awkward, but here it is. -1. Primitives are still primitive. A single value, as discussed. +1. Primitives are still primitive. A single value, as desired. 2. The language allows to access methods and properties of strings, numbers, booleans and symbols. 3. When it happens, a special "object wrapper" is created that provides the functionality and then is destroyed. @@ -67,7 +67,7 @@ Simple, right? And here's what actually happens in `str.toUpperCase()`: So, primitives can provide methods, but they still remain lightweight. -Of course, the JavaScript engine highly optimizes that process. Internally it may skip the creation of the extra object at all, so it's not so costly performance-wise. +Of course, a JavaScript engine highly optimizes that process. Internally it may skip the creation of the extra object at all. But it must adhere to the specification and behave as if it creates one. A number has methods of it's own, for instance, [toFixed(n)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed) rounds the number to the given precision: @@ -80,7 +80,7 @@ alert( n.toFixed(2) ); // 1.23 We'll see more specific methods in next chapters. ````warn header="null/undefined have no methods" -Special types `null` and `undefined` are exceptions. They have no corresponding "wrapper objects" and provide no methods. In a sense, they are "the most primitive". +Special primitives `null` and `undefined` are exceptions. They have no corresponding "wrapper objects" and provide no methods. In a sense, they are "the most primitive". An attempt to access a property of such value would give an error: @@ -91,5 +91,5 @@ alert(null.test); // error ## Summary - Primitives except `null` and `undefined` provide many helpful methods. We plan to study those in the next chapters. -- Formally, these methods work via temporary objects, but JavaScript engines are tuned to optimize that internally, so they are not expensive to call. +- Formally, these methods work via temporary objects, but JavaScript engines are very well tuned to optimize that internally, so they are not expensive to call. diff --git a/1-js/2-first-steps/19-symbol/article.md b/1-js/2-first-steps/19-symbol/article.md new file mode 100644 index 00000000..8dc01365 --- /dev/null +++ b/1-js/2-first-steps/19-symbol/article.md @@ -0,0 +1,193 @@ + +# Symbol type + +A "symbol" represents an unique identifier with a given name. + +A value of this type can be created using `Symbol(name)`: + +```js +// id is a symbol with the name "id" +let id = Symbol("id"); +``` + +Symbols in JavaScript are different from symbols in Ruby language (if you are familiar with it, please don't get trapped by the same word). Two symbols with the same name are not the same: + +```js run +let id1 = Symbol("id"); +let id2 = Symbol("id"); + +*!* +alert(id1 == id2); // false +*/!* +``` + +Symbols is a special primitive type used for identifiers, which are guaranteed to be unique. So, even if we create many symbols with the same name, they are still unique. + +## "Private" properties + +Symbols allow to create concealed, "private" properties of an object, that no other part of code can occasionally access or overwrite. + +For instance, if we want to store an "identifier" for the object `user`, we can create a symbol with the name `id` for it: + +```js run +let user = { name: "John" }; +let id = Symbol("id"); + +user[id] = "ID Value"; +alert( user[id] ); // we can access the data using the symbol as the key +``` + +Now let's imagine that another script wants to have his own "id" property inside `user`, for his own purposes. That may be another javascript library, so the scripts are completely unaware for each other. + +No problem. It can create its own `Symbol("id")`. There will be no conflict, because symbols are always different, even if they have the same name. + +Please note that if we used a string `"id"` instead of a symbol for the same purpose, then there would be a conflict: + +```js run +let user = { name: "John" }; + +// our script uses "id" property +user.id = "ID Value"; + +// ...if later another script the uses "id" for its purposes... + +user.id = "ID 2" +// boom! overwritten! it did not mean to harm the colleague, but did it! +``` + +Two `Symbol("id")` are not equal, that's why they would allow to store values safely. + +**If we want to use a symbol in an object literal, we need square brackets.** + +Like this: + +```js +let id = Symbol("id"); + +let user = { + name: "John", +*!* + [id]: 123 // not just "id: 123" +*/!* +}; +``` +That's because we use the value from the variable `id`, not the string "id". + +**Symbolic properties do not participate in `for..in` loop.** + +For instance: + +```js run +let id = Symbol("id"); +let user = { + name: "John", + age: 30, + [id]: 123 +}; + +*!* +for(let key in user) alert(key); // name, age (no symbols) +*/!* + +// the direct access by the global symbol works +alert( "Direct: " + user[Symbol.for("id")] ); +``` + +That's a part of the general "hiding" concept. So if another script or a library loops over our object, it won't unexpectedly access the symbol property. + +In contrast, [Object.assign](mdn:js/Object/assign) copies both string and symbol properties: + +```js run +let id = Symbol("id"); +let user = { + [id]: 123 +}; + +let clone = Object.assign({}, user); + +alert( clone[id] ); // 123 +``` + +There's no paradox here. That's the expected behavior, because when we clone an object, we await symbol properties (like `id`) to be copied as well. + + +````smart header="Property identifier must be either a string or a symbol" +We can only use strings or symbols as keys in objects. Other types are coerced to strings. + +For instance: + +```js run +let obj = { + 0: "test" // same as "0": "test" +} + +// bot alerts access the same property (the number 0 is converted to string "0") +alert( obj["0"] ); // test +alert( obj[0] ); // test (same property) +``` +```` + + +## Global symbols + +There is a global symbols registry that allows, if necessary, to create common global symbols and access them by their name. + +To read a global symbol, we need to call a built-in method `Symbol.for(name)`. If there is no such symbol, it is created. + +For instance: + +```js run +// read from the global registry +let name = Symbol.for("name"); + +// read it again +let nameAgain = Symbol.for("name"); + +// the same symbol +alert( name === nameAgain ); // true +``` + +If we want an application-wide symbol, accessible everywhere in the code -- that's what the registry is for. + +```smart +In some programming languages, like Ruby, the name identifies the symbol. In Javascript, as we can see, that's true for global symbols. +``` + +The `Symbol.for(name)` call, which returns a symbol by name, there exists the reverse call `Symbol.keyFor(sym)`. It returns the name by the global symbol. + +For instance: + +```js run +let sym = Symbol.for("name"); + +alert( Symbol.keyFor(sym) ); // name +``` + +````warn header="`Symbol.keyFor` returns `undefined` for non-global symbols" +The `Symbol.keyFor` method works only for global symbols. Otherwise it returns `undefined`, like here: + +```js run +alert( Symbol.keyFor(Symbol.for("name")) ); // name, global symbol +alert( Symbol.keyFor(Symbol("name2")) ); // undefined, non-global symbol +``` + +In practice, that's fine, because the name of the symbol, if it's not global, is generally not used except for debugging purposes. +```` + +## System symbols + +There exist many "system" symbols that Javascript uses internally, and we can use them to fine-tune various aspects of our objects. + +They are listed in the specification in the [Well-known symbols](https://tc39.github.io/ecma262/#sec-well-known-symbols) table. For instance, `Symbol.toPrimitive` allows to describe object to primitive conversion. We'll see its use very soon. Other symbols will become more obvious as we'll study the corresponding language features. + +## Summary + +- Symbol is a primitive type for unique identifiers. +- Symbols are created with `Symbol(name)` call. +- Symbols are useful if we want to create a field that only those who know the symbol can access. +- Symbols created with `Symbol(name)` are always different, even if they have the same name. If we want same-named symbols to be equal, then we should use the global registry: `Symbol.for(name)` returns (creates if needed) a global symbol with the given name. Multiple calls return the same symbol. +- There are system symbols used by Javascript and accessible as `Symbol.*`. We can use them to alter some built-in behaviors. + +Symbols don't appear in `for..in` loops. As we'll see further, there are other means to get object properties which also ignore symbols, so they remain hidden. + +Technically though, there is still a way to discover all symbols of an object with a build-in method [Object.getOwnPropertySymbols](mdn:js/Object/getOwnPropertySymbols). So they are not completely hidden and private. But most scripts and built-in methods adhere to a common agreement that they are. And the one who explicitly calls a method with such a cumbersome name probably knows what he's doing. diff --git a/1-js/2-first-steps/21-object-tostring-valueof/article.md b/1-js/2-first-steps/20-object-tostring-valueof/article.md similarity index 98% rename from 1-js/2-first-steps/21-object-tostring-valueof/article.md rename to 1-js/2-first-steps/20-object-tostring-valueof/article.md index 9d6f7029..e06cc3d5 100644 --- a/1-js/2-first-steps/21-object-tostring-valueof/article.md +++ b/1-js/2-first-steps/20-object-tostring-valueof/article.md @@ -1,9 +1,9 @@ # Object to primitive conversion -In the chapter we've seen the rules for numeric, string and boolean conversions. +In the chapter we've seen the rules for numeric, string and boolean conversions of primitives. -But we left a gap for objects. Now let's close it. +But we left a gap for objects. Now let's fill it. [cut] diff --git a/1-js/2-first-steps/10-comparison/1-comparison-questions/solution.md b/1-js/2-first-steps/8-comparison/1-comparison-questions/solution.md similarity index 100% rename from 1-js/2-first-steps/10-comparison/1-comparison-questions/solution.md rename to 1-js/2-first-steps/8-comparison/1-comparison-questions/solution.md diff --git a/1-js/2-first-steps/10-comparison/1-comparison-questions/task.md b/1-js/2-first-steps/8-comparison/1-comparison-questions/task.md similarity index 100% rename from 1-js/2-first-steps/10-comparison/1-comparison-questions/task.md rename to 1-js/2-first-steps/8-comparison/1-comparison-questions/task.md diff --git a/1-js/2-first-steps/10-comparison/article.md b/1-js/2-first-steps/8-comparison/article.md similarity index 100% rename from 1-js/2-first-steps/10-comparison/article.md rename to 1-js/2-first-steps/8-comparison/article.md diff --git a/1-js/2-first-steps/12-uibasic/1-simple-page/solution.md b/1-js/2-first-steps/9-uibasic/1-simple-page/solution.md similarity index 100% rename from 1-js/2-first-steps/12-uibasic/1-simple-page/solution.md rename to 1-js/2-first-steps/9-uibasic/1-simple-page/solution.md diff --git a/1-js/2-first-steps/12-uibasic/1-simple-page/task.md b/1-js/2-first-steps/9-uibasic/1-simple-page/task.md similarity index 100% rename from 1-js/2-first-steps/12-uibasic/1-simple-page/task.md rename to 1-js/2-first-steps/9-uibasic/1-simple-page/task.md diff --git a/1-js/2-first-steps/12-uibasic/article.md b/1-js/2-first-steps/9-uibasic/article.md similarity index 99% rename from 1-js/2-first-steps/12-uibasic/article.md rename to 1-js/2-first-steps/9-uibasic/article.md index 783c936a..b48e248b 100644 --- a/1-js/2-first-steps/12-uibasic/article.md +++ b/1-js/2-first-steps/9-uibasic/article.md @@ -19,7 +19,7 @@ This shows a message and pauses the script execution until the user presses "OK" For example: ```js run -alert( "Hello" ); +alert("Hello"); ``` The small window with the message is called a *modal window*. The word "modal" means that the visitor can't interact with the rest of the page, press other buttons etc, until he deals with the window. In this case -- until he presses "OK". diff --git a/1-js/4-data-structures/4-object/2-is-empty/_js.view/solution.js b/1-js/4-data-structures/4-object2/2-is-empty/_js.view/solution.js similarity index 100% rename from 1-js/4-data-structures/4-object/2-is-empty/_js.view/solution.js rename to 1-js/4-data-structures/4-object2/2-is-empty/_js.view/solution.js diff --git a/1-js/4-data-structures/4-object/2-is-empty/_js.view/test.js b/1-js/4-data-structures/4-object2/2-is-empty/_js.view/test.js similarity index 100% rename from 1-js/4-data-structures/4-object/2-is-empty/_js.view/test.js rename to 1-js/4-data-structures/4-object2/2-is-empty/_js.view/test.js diff --git a/1-js/4-data-structures/4-object/2-is-empty/solution.md b/1-js/4-data-structures/4-object2/2-is-empty/solution.md similarity index 100% rename from 1-js/4-data-structures/4-object/2-is-empty/solution.md rename to 1-js/4-data-structures/4-object2/2-is-empty/solution.md diff --git a/1-js/4-data-structures/4-object/2-is-empty/task.md b/1-js/4-data-structures/4-object2/2-is-empty/task.md similarity index 100% rename from 1-js/4-data-structures/4-object/2-is-empty/task.md rename to 1-js/4-data-structures/4-object2/2-is-empty/task.md diff --git a/1-js/4-data-structures/4-object/3-sum-salaries/_js.view/solution.js b/1-js/4-data-structures/4-object2/3-sum-salaries/_js.view/solution.js similarity index 100% rename from 1-js/4-data-structures/4-object/3-sum-salaries/_js.view/solution.js rename to 1-js/4-data-structures/4-object2/3-sum-salaries/_js.view/solution.js diff --git a/1-js/4-data-structures/4-object/3-sum-salaries/_js.view/test.js b/1-js/4-data-structures/4-object2/3-sum-salaries/_js.view/test.js similarity index 100% rename from 1-js/4-data-structures/4-object/3-sum-salaries/_js.view/test.js rename to 1-js/4-data-structures/4-object2/3-sum-salaries/_js.view/test.js diff --git a/1-js/4-data-structures/4-object/3-sum-salaries/solution.md b/1-js/4-data-structures/4-object2/3-sum-salaries/solution.md similarity index 100% rename from 1-js/4-data-structures/4-object/3-sum-salaries/solution.md rename to 1-js/4-data-structures/4-object2/3-sum-salaries/solution.md diff --git a/1-js/4-data-structures/4-object/3-sum-salaries/task.md b/1-js/4-data-structures/4-object2/3-sum-salaries/task.md similarity index 100% rename from 1-js/4-data-structures/4-object/3-sum-salaries/task.md rename to 1-js/4-data-structures/4-object2/3-sum-salaries/task.md diff --git a/1-js/4-data-structures/4-object/4-max-salary/_js.view/solution.js b/1-js/4-data-structures/4-object2/4-max-salary/_js.view/solution.js similarity index 100% rename from 1-js/4-data-structures/4-object/4-max-salary/_js.view/solution.js rename to 1-js/4-data-structures/4-object2/4-max-salary/_js.view/solution.js diff --git a/1-js/4-data-structures/4-object/4-max-salary/_js.view/test.js b/1-js/4-data-structures/4-object2/4-max-salary/_js.view/test.js similarity index 100% rename from 1-js/4-data-structures/4-object/4-max-salary/_js.view/test.js rename to 1-js/4-data-structures/4-object2/4-max-salary/_js.view/test.js diff --git a/1-js/4-data-structures/4-object/4-max-salary/solution.md b/1-js/4-data-structures/4-object2/4-max-salary/solution.md similarity index 100% rename from 1-js/4-data-structures/4-object/4-max-salary/solution.md rename to 1-js/4-data-structures/4-object2/4-max-salary/solution.md diff --git a/1-js/4-data-structures/4-object/4-max-salary/task.md b/1-js/4-data-structures/4-object2/4-max-salary/task.md similarity index 100% rename from 1-js/4-data-structures/4-object/4-max-salary/task.md rename to 1-js/4-data-structures/4-object2/4-max-salary/task.md diff --git a/1-js/4-data-structures/4-object/5-count-properties/_js.view/solution.js b/1-js/4-data-structures/4-object2/5-count-properties/_js.view/solution.js similarity index 100% rename from 1-js/4-data-structures/4-object/5-count-properties/_js.view/solution.js rename to 1-js/4-data-structures/4-object2/5-count-properties/_js.view/solution.js diff --git a/1-js/4-data-structures/4-object/5-count-properties/_js.view/test.js b/1-js/4-data-structures/4-object2/5-count-properties/_js.view/test.js similarity index 100% rename from 1-js/4-data-structures/4-object/5-count-properties/_js.view/test.js rename to 1-js/4-data-structures/4-object2/5-count-properties/_js.view/test.js diff --git a/1-js/4-data-structures/4-object/5-count-properties/solution.md b/1-js/4-data-structures/4-object2/5-count-properties/solution.md similarity index 100% rename from 1-js/4-data-structures/4-object/5-count-properties/solution.md rename to 1-js/4-data-structures/4-object2/5-count-properties/solution.md diff --git a/1-js/4-data-structures/4-object/5-count-properties/task.md b/1-js/4-data-structures/4-object2/5-count-properties/task.md similarity index 100% rename from 1-js/4-data-structures/4-object/5-count-properties/task.md rename to 1-js/4-data-structures/4-object2/5-count-properties/task.md diff --git a/1-js/4-data-structures/4-object/6-multiply-numeric/_js.view/solution.js b/1-js/4-data-structures/4-object2/6-multiply-numeric/_js.view/solution.js similarity index 100% rename from 1-js/4-data-structures/4-object/6-multiply-numeric/_js.view/solution.js rename to 1-js/4-data-structures/4-object2/6-multiply-numeric/_js.view/solution.js diff --git a/1-js/4-data-structures/4-object/6-multiply-numeric/_js.view/source.js b/1-js/4-data-structures/4-object2/6-multiply-numeric/_js.view/source.js similarity index 100% rename from 1-js/4-data-structures/4-object/6-multiply-numeric/_js.view/source.js rename to 1-js/4-data-structures/4-object2/6-multiply-numeric/_js.view/source.js diff --git a/1-js/4-data-structures/4-object/6-multiply-numeric/_js.view/test.js b/1-js/4-data-structures/4-object2/6-multiply-numeric/_js.view/test.js similarity index 100% rename from 1-js/4-data-structures/4-object/6-multiply-numeric/_js.view/test.js rename to 1-js/4-data-structures/4-object2/6-multiply-numeric/_js.view/test.js diff --git a/1-js/4-data-structures/4-object/6-multiply-numeric/solution.md b/1-js/4-data-structures/4-object2/6-multiply-numeric/solution.md similarity index 100% rename from 1-js/4-data-structures/4-object/6-multiply-numeric/solution.md rename to 1-js/4-data-structures/4-object2/6-multiply-numeric/solution.md diff --git a/1-js/4-data-structures/4-object/6-multiply-numeric/task.md b/1-js/4-data-structures/4-object2/6-multiply-numeric/task.md similarity index 100% rename from 1-js/4-data-structures/4-object/6-multiply-numeric/task.md rename to 1-js/4-data-structures/4-object2/6-multiply-numeric/task.md diff --git a/1-js/4-data-structures/4-object/article.md b/1-js/4-data-structures/4-object2/article.md similarity index 100% rename from 1-js/4-data-structures/4-object/article.md rename to 1-js/4-data-structures/4-object2/article.md diff --git a/1-js/2-first-steps/11-destructuring/1-destructuring-assignment/solution.md b/archive/11-destructuring/1-destructuring-assignment/solution.md similarity index 100% rename from 1-js/2-first-steps/11-destructuring/1-destructuring-assignment/solution.md rename to archive/11-destructuring/1-destructuring-assignment/solution.md diff --git a/1-js/2-first-steps/11-destructuring/1-destructuring-assignment/task.md b/archive/11-destructuring/1-destructuring-assignment/task.md similarity index 100% rename from 1-js/2-first-steps/11-destructuring/1-destructuring-assignment/task.md rename to archive/11-destructuring/1-destructuring-assignment/task.md diff --git a/1-js/2-first-steps/11-destructuring/article.md b/archive/11-destructuring/article.md similarity index 100% rename from 1-js/2-first-steps/11-destructuring/article.md rename to archive/11-destructuring/article.md diff --git a/figures.sketch b/figures.sketch index dde9a827..e8922a01 100644 Binary files a/figures.sketch and b/figures.sketch differ