diff --git a/1-js/02-first-steps/04-variables/article.md b/1-js/02-first-steps/04-variables/article.md index d7781f11f..aef68ed41 100644 --- a/1-js/02-first-steps/04-variables/article.md +++ b/1-js/02-first-steps/04-variables/article.md @@ -28,7 +28,11 @@ Endi `=` tayinlash operatori yordamida unga ba'zi ma'lumotlarni kiritishimiz mum let message; *!* +<<<<<<< HEAD message = 'Hello'; // matni saqlash +======= +message = 'Hello'; // store the string 'Hello' in the variable named message +>>>>>>> 4d01fc20d4d82358e61518a31efe80dec9bb2602 */!* ``` diff --git a/1-js/02-first-steps/13-while-for/article.md b/1-js/02-first-steps/13-while-for/article.md index a3a1d0b6d..e06b7c89d 100644 --- a/1-js/02-first-steps/13-while-for/article.md +++ b/1-js/02-first-steps/13-while-for/article.md @@ -119,6 +119,7 @@ Keling, `for` ifodani qisma ko'rib chiqamiz: | qism | | | |-------|----------|----------------------------------------------------------------------------| +<<<<<<< HEAD <<<<<<< HEAD:1-js/02-first-steps/12-while-for/article.md | boshlanishi | `i = 0` | Tsikldan e'lon qilingandan keyin bir marta bajariladi. | | shart | `i < 3`| Har bir tsikl takrorlashdan oldin tekshiriladi. Agar yolg'on bo'lsa, tsikl to'xtaydi. | @@ -129,6 +130,9 @@ Keling, `for` ifodani qisma ko'rib chiqamiz: Umumiy tsikl algoritmi quyidagicha ishlaydi: ======= | begin | `i = 0` | Executes once upon entering the loop. | +======= +| begin | `let i = 0` | Executes once upon entering the loop. | +>>>>>>> 4d01fc20d4d82358e61518a31efe80dec9bb2602 | condition | `i < 3`| Checked before every loop iteration. If false, the loop stops. | | body | `alert(i)`| Runs again and again while the condition is truthy. | | step| `i++` | Executes after the body on each iteration. | @@ -438,7 +442,7 @@ label: { } ``` -...Although, 99.9% of the time `break` used is inside loops, as we've seen in the examples above. +...Although, 99.9% of the time `break` is used inside loops, as we've seen in the examples above. A `continue` is only possible from inside a loop. >>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c:1-js/02-first-steps/13-while-for/article.md diff --git a/1-js/02-first-steps/15-function-basics/article.md b/1-js/02-first-steps/15-function-basics/article.md index 7275fd7f4..7b5bff049 100644 --- a/1-js/02-first-steps/15-function-basics/article.md +++ b/1-js/02-first-steps/15-function-basics/article.md @@ -213,7 +213,7 @@ In other words, to put these terms straight: We declare functions listing their parameters, then call them passing arguments. -In the example above, one might say: "the function `sayMessage` is declared with two parameters, then called with two arguments: `from` and `"Hello"`". +In the example above, one might say: "the function `showMessage` is declared with two parameters, then called with two arguments: `from` and `"Hello"`". ## Default values @@ -304,6 +304,7 @@ function showMessage(text) { showMessage(); // empty message ``` +<<<<<<< HEAD <<<<<<< HEAD:1-js/02-first-steps/14-function-basics/article.md ...Yoki `||` operatori: @@ -313,6 +314,9 @@ function showMessage(from, text) { text = text || 'matn berilmagan'; ======= ...Or we could use the `??` operator: +======= +...Or we could use the `||` operator: +>>>>>>> 4d01fc20d4d82358e61518a31efe80dec9bb2602 ```js function showMessage(text) { diff --git a/1-js/03-code-quality/06-polyfills/article.md b/1-js/03-code-quality/06-polyfills/article.md index c705d0d6d..af11faf31 100644 --- a/1-js/03-code-quality/06-polyfills/article.md +++ b/1-js/03-code-quality/06-polyfills/article.md @@ -53,7 +53,7 @@ Here, in this chapter, our purpose is to get the gist of how they work, and thei ## Transpilers -A [transpiler](https://en.wikipedia.org/wiki/Source-to-source_compiler) is a special piece of software that can parse ("read and understand") modern code, and rewrite it using older syntax constructs, so that the result would be the same. +A [transpiler](https://en.wikipedia.org/wiki/Source-to-source_compiler) is a special piece of software that translates source code to another source code. It can parse ("read and understand") modern code and rewrite it using older syntax constructs, so that it'll also work in outdated engines. E.g. JavaScript before year 2020 didn't have the "nullish coalescing operator" `??`. So, if a visitor uses an outdated browser, it may fail to understand the code like `height = height ?? 100`. diff --git a/1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/task.md b/1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/task.md index 77e1226aa..43b94d2fe 100644 --- a/1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/task.md +++ b/1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/task.md @@ -4,7 +4,11 @@ importance: 2 # Ikki funktsiya - bitta obyekt +<<<<<<< HEAD `A` va `B` funktsiyalarini `new A()==new B()` kabi yaratish mumkinmi? +======= +Is it possible to create functions `A` and `B` so that `new A() == new B()`? +>>>>>>> 4d01fc20d4d82358e61518a31efe80dec9bb2602 ```js no-beautify function A() { ... } diff --git a/1-js/04-object-basics/09-object-toprimitive/article.md b/1-js/04-object-basics/09-object-toprimitive/article.md new file mode 100644 index 000000000..3e52a1d51 --- /dev/null +++ b/1-js/04-object-basics/09-object-toprimitive/article.md @@ -0,0 +1,277 @@ + +# Object to primitive conversion + +What happens when objects are added `obj1 + obj2`, subtracted `obj1 - obj2` or printed using `alert(obj)`? + +JavaScript doesn't exactly allow to customize how operators work on objects. Unlike some other programming languages, such as Ruby or C++, we can't implement a special object method to handle an addition (or other operators). + +In case of such operations, objects are auto-converted to primitives, and then the operation is carried out over these primitives and results in a primitive value. + +That's an important limitation, as the result of `obj1 + obj2` can't be another object! + +E.g. we can't make objects representing vectors or matrices (or achievements or whatever), add them and expect a "summed" object as the result. Such architectural feats are automatically "off the board". + +So, because we can't do much here, there's no maths with objects in real projects. When it happens, it's usually because of a coding mistake. + +In this chapter we'll cover how an object converts to primitive and how to customize it. + +We have two purposes: + +1. It will allow us to understand what's going on in case of coding mistakes, when such an operation happened accidentally. +2. There are exceptions, where such operations are possible and look good. E.g. subtracting or comparing dates (`Date` objects). We'll come across them later. + +## Conversion rules + +In the chapter we've seen the rules for numeric, string and boolean conversions of primitives. But we left a gap for objects. Now, as we know about methods and symbols it becomes possible to fill it. + +1. All objects are `true` in a boolean context. There are only numeric and string conversions. +2. The numeric conversion happens when we subtract objects or apply mathematical functions. For instance, `Date` objects (to be covered in the chapter ) can be subtracted, and the result of `date1 - date2` is the time difference between two dates. +3. As for the string conversion -- it usually happens when we output an object like `alert(obj)` and in similar contexts. + +We can fine-tune string and numeric conversion, using special object methods. + +There are three variants of type conversion, that happen in various situations. + +They're called "hints", as described in the [specification](https://tc39.github.io/ecma262/#sec-toprimitive): + +`"string"` +: For an object-to-string conversion, when we're doing an operation on an object that expects a string, like `alert`: + + ```js + // output + alert(obj); + + // using object as a property key + anotherObj[obj] = 123; + ``` + +`"number"` +: For an object-to-number conversion, like when we're doing maths: + + ```js + // explicit conversion + let num = Number(obj); + + // maths (except binary plus) + let n = +obj; // unary plus + let delta = date1 - date2; + + // less/greater comparison + let greater = user1 > user2; + ``` + +`"default"` +: Occurs in rare cases when the operator is "not sure" what type to expect. + + For instance, binary plus `+` can work both with strings (concatenates them) and numbers (adds them), so both strings and numbers would do. So if a binary plus gets an object as an argument, it uses the `"default"` hint to convert it. + + Also, if an object is compared using `==` with a string, number or a symbol, it's also unclear which conversion should be done, so the `"default"` hint is used. + + ```js + // binary plus uses the "default" hint + let total = obj1 + obj2; + + // obj == number uses the "default" hint + if (user == 1) { ... }; + ``` + + The greater and less comparison operators, such as `<` `>`, can work with both strings and numbers too. Still, they use the `"number"` hint, not `"default"`. That's for historical reasons. + + In practice though, we don't need to remember these peculiar details, because all built-in objects except for one case (`Date` object, we'll learn it later) implement `"default"` conversion the same way as `"number"`. And we can do the same. + +```smart header="No `\"boolean\"` hint" +Please note -- there are only three hints. It's that simple. + +There is no "boolean" hint (all objects are `true` in boolean context) or anything else. And if we treat `"default"` and `"number"` the same, like most built-ins do, then there are only two conversions. +``` + +**To do the conversion, JavaScript tries to find and call three object methods:** + +1. Call `obj[Symbol.toPrimitive](hint)` - the method with the symbolic key `Symbol.toPrimitive` (system symbol), if such method exists, +2. Otherwise if hint is `"string"` + - try `obj.toString()` and `obj.valueOf()`, whatever exists. +3. Otherwise if hint is `"number"` or `"default"` + - try `obj.valueOf()` and `obj.toString()`, whatever exists. + +## Symbol.toPrimitive + +Let's start from the first method. There's a built-in symbol named `Symbol.toPrimitive` that should be used to name the conversion method, like this: + +```js +obj[Symbol.toPrimitive] = function(hint) { + // here goes the code to convert this object to a primitive + // it must return a primitive value + // hint = one of "string", "number", "default" +}; +``` + +If the method `Symbol.toPrimitive` exists, it's used for all hints, and no more methods are needed. + +For instance, here `user` object implements it: + +```js run +let user = { + name: "John", + money: 1000, + + [Symbol.toPrimitive](hint) { + alert(`hint: ${hint}`); + return hint == "string" ? `{name: "${this.name}"}` : this.money; + } +}; + +// conversions demo: +alert(user); // hint: string -> {name: "John"} +alert(+user); // hint: number -> 1000 +alert(user + 500); // hint: default -> 1500 +``` + +As we can see from the code, `user` becomes a self-descriptive string or a money amount depending on the conversion. The single method `user[Symbol.toPrimitive]` handles all conversion cases. + + +## toString/valueOf + +If there's no `Symbol.toPrimitive` then JavaScript tries to find methods `toString` and `valueOf`: + +- For the "string" hint: `toString`, and if it doesn't exist, then `valueOf` (so `toString` has the priority for string conversions). +- For other hints: `valueOf`, and if it doesn't exist, then `toString` (so `valueOf` has the priority for maths). + +Methods `toString` and `valueOf` come from ancient times. They are not symbols (symbols did not exist that long ago), but rather "regular" string-named methods. They provide an alternative "old-style" way to implement the conversion. + +These methods must return a primitive value. If `toString` or `valueOf` returns an object, then it's ignored (same as if there were no method). + +By default, a plain object has following `toString` and `valueOf` methods: + +- The `toString` method returns a string `"[object Object]"`. +- The `valueOf` method returns the object itself. + +Here's the demo: + +```js run +let user = {name: "John"}; + +alert(user); // [object Object] +alert(user.valueOf() === user); // true +``` + +So if we try to use an object as a string, like in an `alert` or so, then by default we see `[object Object]`. + +The default `valueOf` is mentioned here only for the sake of completeness, to avoid any confusion. As you can see, it returns the object itself, and so is ignored. Don't ask me why, that's for historical reasons. So we can assume it doesn't exist. + +Let's implement these methods to customize the conversion. + +For instance, here `user` does the same as above using a combination of `toString` and `valueOf` instead of `Symbol.toPrimitive`: + +```js run +let user = { + name: "John", + money: 1000, + + // for hint="string" + toString() { + return `{name: "${this.name}"}`; + }, + + // for hint="number" or "default" + valueOf() { + return this.money; + } + +}; + +alert(user); // toString -> {name: "John"} +alert(+user); // valueOf -> 1000 +alert(user + 500); // valueOf -> 1500 +``` + +As we can see, the behavior is the same as the previous example with `Symbol.toPrimitive`. + +Often we want a single "catch-all" place to handle all primitive conversions. In this case, we can implement `toString` only, like this: + +```js run +let user = { + name: "John", + + toString() { + return this.name; + } +}; + +alert(user); // toString -> John +alert(user + 500); // toString -> John500 +``` + +In the absence of `Symbol.toPrimitive` and `valueOf`, `toString` will handle all primitive conversions. + +### A conversion can return any primitive type + +The important thing to know about all primitive-conversion methods is that they do not necessarily return the "hinted" primitive. + +There is no control whether `toString` returns exactly a string, or whether `Symbol.toPrimitive` method returns a number for a hint `"number"`. + +The only mandatory thing: these methods must return a primitive, not an object. + +```smart header="Historical notes" +For historical reasons, if `toString` or `valueOf` returns an object, there's no error, but such value is ignored (like if the method didn't exist). That's because in ancient times there was no good "error" concept in JavaScript. + +In contrast, `Symbol.toPrimitive` *must* return a primitive, otherwise there will be an error. +``` + +## Further conversions + +As we know already, many operators and functions perform type conversions, e.g. multiplication `*` converts operands to numbers. + +If we pass an object as an argument, then there are two stages: +1. The object is converted to a primitive (using the rules described above). +2. If the resulting primitive isn't of the right type, it's converted. + +For instance: + +```js run +let obj = { + // toString handles all conversions in the absence of other methods + toString() { + return "2"; + } +}; + +alert(obj * 2); // 4, object converted to primitive "2", then multiplication made it a number +``` + +1. The multiplication `obj * 2` first converts the object to primitive (that's a string `"2"`). +2. Then `"2" * 2` becomes `2 * 2` (the string is converted to number). + +Binary plus will concatenate strings in the same situation, as it gladly accepts a string: + +```js run +let obj = { + toString() { + return "2"; + } +}; + +alert(obj + 2); // 22 ("2" + 2), conversion to primitive returned a string => concatenation +``` + +## Summary + +The object-to-primitive conversion is called automatically by many built-in functions and operators that expect a primitive as a value. + +There are 3 types (hints) of it: +- `"string"` (for `alert` and other operations that need a string) +- `"number"` (for maths) +- `"default"` (few operators) + +The specification describes explicitly which operator uses which hint. There are very few operators that "don't know what to expect" and use the `"default"` hint. Usually for built-in objects `"default"` hint is handled the same way as `"number"`, so in practice the last two are often merged together. + +The conversion algorithm is: + +1. Call `obj[Symbol.toPrimitive](hint)` if the method exists, +2. Otherwise if hint is `"string"` + - try `obj.toString()` and `obj.valueOf()`, whatever exists. +3. Otherwise if hint is `"number"` or `"default"` + - try `obj.valueOf()` and `obj.toString()`, whatever exists. + +In practice, it's often enough to implement only `obj.toString()` as a "catch-all" method for string conversions that should return a "human-readable" representation of an object, for logging or debugging purposes. + +As for math operations, JavaScript doesn't provide a way to "override" them using methods, so real life projects rarely use them on objects. diff --git a/1-js/05-data-types/02-number/article.md b/1-js/05-data-types/02-number/article.md index b9a97318f..9ba57cfa2 100644 --- a/1-js/05-data-types/02-number/article.md +++ b/1-js/05-data-types/02-number/article.md @@ -9,7 +9,7 @@ In modern JavaScript, there are two types of numbers: 1. Regular numbers in JavaScript are stored in 64-bit format [IEEE-754](https://en.wikipedia.org/wiki/IEEE_754-2008_revision), also known as "double precision floating point numbers". These are numbers that we're using most of the time, and we'll talk about them in this chapter. -2. BigInt numbers, to represent integers of arbitrary length. They are sometimes needed, because a regular number can't exceed 253 or be less than -253. As bigints are used in few special areas, we devote them a special chapter . +2. BigInt numbers, to represent integers of arbitrary length. They are sometimes needed, because a regular number can't safely exceed 253 or be less than -253. As bigints are used in few special areas, we devote them a special chapter . So here we'll talk about regular numbers. Let's expand our knowledge of them. >>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c @@ -56,8 +56,8 @@ In other words, `e` multiplies the number by `1` with the given zeroes count. >>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c ```js -1e3 = 1 * 1000 // e3 means *1000 -1.23e6 = 1.23 * 1000000 // e6 means *1000000 +1e3 === 1 * 1000; // e3 means *1000 +1.23e6 === 1.23 * 1000000; // e6 means *1000000 ``` <<<<<<< HEAD @@ -81,16 +81,28 @@ Just like before, using `"e"` can help. If we'd like to avoid writing the zeroes let ms = 1e-6; // 1 dan chapga oltita nol ``` +<<<<<<< HEAD Agar `0.000001` dagi nollarni hisoblasak, ularning soni 6 taga teng. Tabiiyki, bu `1e-6`. +======= +If we count the zeroes in `0.000001`, there are 6 of them. So naturally it's `1e-6`. +>>>>>>> 4d01fc20d4d82358e61518a31efe80dec9bb2602 Boshqacha qilib aytganda, `"e"` dan keyin salbiy son, berilgan nol soni bilan 1 ga bo'linishni anglatadi: ```js +<<<<<<< HEAD // -3 3 ta nol bilan 1 ga bo'linadi 1e-3 = 1 / 1000 (=0.001) // -6 6 ta nol bilan 1 ga bo'linadi 1.23e-6 = 1.23 / 1000000 (=0.00000123) +======= +// -3 divides by 1 with 3 zeroes +1e-3 === 1 / 1000; // 0.001 + +// -6 divides by 1 with 6 zeroes +1.23e-6 === 1.23 / 1000000; // 0.00000123 +>>>>>>> 4d01fc20d4d82358e61518a31efe80dec9bb2602 ``` ### O'n olti, ikkilik va sakkizli sonlar @@ -145,7 +157,12 @@ Iltimos e'tibor bering, `123456..toString(36)` dagi ikkita nuqta matn terish xat Agar bitta nuqta qo'ygan bo'lsak: `123456.toString(36)`, unda xato bo'lishi mumkin, chunki JavaScript sintaksisida birinchi nuqtadan keyingi o'nlik qismi nazarda tutilgan. Agar biz yana bitta nuqta qo'yadigan bo'lsak, JavaScript kasr qismi bo'sh ekanligini biladi va endi usulga o'tadi. +<<<<<<< HEAD Shuningdek yozishi mumkin edi `(123456).toString(36)`. +======= +Also could write `(123456).toString(36)`. + +>>>>>>> 4d01fc20d4d82358e61518a31efe80dec9bb2602 ``` ## Yaxlitlash @@ -389,7 +406,11 @@ let num = +prompt("Raqam kiriting", ''); alert( isFinite(num) ); ``` +<<<<<<< HEAD Iltimos, barcha raqam;o funktsiyalarda bo'sh yoki faqat bo'shliq matni `0` sifatida ko'rib chiqilishini unutmang. +======= +Please note that an empty or a space-only string is treated as `0` in all numeric functions including `isFinite`. +>>>>>>> 4d01fc20d4d82358e61518a31efe80dec9bb2602 ```smart header="`Object.is` bilan solishtiring" diff --git a/1-js/05-data-types/05-array-methods/12-reduce-object/task.md b/1-js/05-data-types/05-array-methods/12-reduce-object/task.md index d3c8f8eb1..7f0082357 100644 --- a/1-js/05-data-types/05-array-methods/12-reduce-object/task.md +++ b/1-js/05-data-types/05-array-methods/12-reduce-object/task.md @@ -4,7 +4,7 @@ importance: 4 # Create keyed object from array -Let's say we received an array of users in the form `{id:..., name:..., age... }`. +Let's say we received an array of users in the form `{id:..., name:..., age:... }`. Create a function `groupById(arr)` that creates an object from it, with `id` as the key, and array items as values. diff --git a/1-js/05-data-types/09-keys-values-entries/article.md b/1-js/05-data-types/09-keys-values-entries/article.md index 0aaefee5a..3fca86445 100644 --- a/1-js/05-data-types/09-keys-values-entries/article.md +++ b/1-js/05-data-types/09-keys-values-entries/article.md @@ -104,7 +104,7 @@ Objects lack many methods that exist for arrays, e.g. `map`, `filter` and others If we'd like to apply them, then we can use `Object.entries` followed by `Object.fromEntries`: 1. Use `Object.entries(obj)` to get an array of key/value pairs from `obj`. -2. Use array methods on that array, e.g. `map`. +2. Use array methods on that array, e.g. `map`, to transform these key/value pairs. 3. Use `Object.fromEntries(array)` on the resulting array to turn it back into an object. For example, we have an object with prices, and would like to double them: @@ -118,13 +118,18 @@ let prices = { *!* let doublePrices = Object.fromEntries( - // convert to array, map, and then fromEntries gives back the object - Object.entries(prices).map(([key, value]) => [key, value * 2]) + // convert prices to array, map each key/value pair into another pair + // and then fromEntries gives back the object + Object.entries(prices).map(entry => [entry[0], entry[1] * 2]) ); */!* alert(doublePrices.meat); // 8 -``` +``` +<<<<<<< HEAD It may look difficult at first sight, but becomes easy to understand after you use it once or twice. We can make powerful chains of transforms this way. >>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c:1-js/05-data-types/09-keys-values-entries/article.md +======= +It may look difficult at first sight, but becomes easy to understand after you use it once or twice. We can make powerful chains of transforms this way. +>>>>>>> 4d01fc20d4d82358e61518a31efe80dec9bb2602 diff --git a/1-js/06-advanced-functions/04-var/article.md b/1-js/06-advanced-functions/04-var/article.md index fabee73ac..f5e6ee44d 100644 --- a/1-js/06-advanced-functions/04-var/article.md +++ b/1-js/06-advanced-functions/04-var/article.md @@ -7,7 +7,7 @@ ```smart header="This article is for understanding old scripts" The information in this article is useful for understanding old scripts. -That's not how we write a new code. +That's not how we write new code. ``` In the very first chapter about [variables](info:variables), we mentioned three ways of variable declaration: diff --git a/1-js/07-object-properties/01-property-descriptors/article.md b/1-js/07-object-properties/01-property-descriptors/article.md index 6ca0ea32b..f166a4737 100644 --- a/1-js/07-object-properties/01-property-descriptors/article.md +++ b/1-js/07-object-properties/01-property-descriptors/article.md @@ -29,7 +29,11 @@ Biz ularni hali ko'rmadik, chunki umuman ular ko'rinmaydi. "Odatiy usul" xususiy Birinchidan, ushbu bayroqlarni qanday olish kerakligini ko'rib chiqamiz. +<<<<<<< HEAD [Object.getOwnPropertyDescriptor](mdn:js/Object/getOwnPropertyDescriptor) usuli xususiyat haqida *to'liq* ma'lumotni so'rashga imkon beradi. +======= +The method [Object.getOwnPropertyDescriptor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptor) allows to query the *full* information about a property. +>>>>>>> 4d01fc20d4d82358e61518a31efe80dec9bb2602 Sintaksis: ```js @@ -64,7 +68,11 @@ alert( JSON.stringify(descriptor, null, 2 ) ); */ ``` +<<<<<<< HEAD Bayroqlarni o'zgartirish uchun biz [Object.defineProperty](mdn:js/Object/defineProperty) dan foydalanishimiz mumkin. +======= +To change the flags, we can use [Object.defineProperty](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty). +>>>>>>> 4d01fc20d4d82358e61518a31efe80dec9bb2602 Sintaksis: @@ -242,9 +250,13 @@ Konfiguratsiya qilinmaydigan bayroq (`configurable: false`) ba'zan o'rnatilgan o <<<<<<< HEAD Konfiguratsiya qilinmaydigan xususiyatni o'chirib bo'lmaydi yoki `defineProperty` bilan o'zgartirib bo'lmaydi. +<<<<<<< HEAD Masalan, `Math.PI` ni faqat o'qish mumkin, hisoblab bo'lmaydi va konfiguratsiya qilinmaydi: ======= A non-configurable property can not be deleted. +======= +A non-configurable property can't be deleted, its attributes can't be modified. +>>>>>>> 4d01fc20d4d82358e61518a31efe80dec9bb2602 For instance, `Math.PI` is non-writable, non-enumerable and non-configurable: >>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c @@ -265,25 +277,32 @@ alert( JSON.stringify(descriptor, null, 2 ) ); Shunday qilib, dasturchi `Math.PI` qiymatini o'zgartira olmaydi yoki uning ustiga yozib bo'lmaydi. ```js run -Math.PI = 3; // Error +Math.PI = 3; // Error, because it has writable: false // delete Math.PI ham ishlamaydi ``` +<<<<<<< HEAD <<<<<<< HEAD Mulkni konfiguratsiya qilinmaydigan qilish - bu bir tomonlama yo'l. Biz uni o'zgartira olmaymiz, chunki `defineProperty` konfiguratsiya qilinmaydigan xususiyatlarda ishlamaydi. Bu erda biz `user.name` manzilini "abadiy muhrlangan" konstantaga keltiramiz: ======= Making a property non-configurable is a one-way road. We cannot change it back with `defineProperty`. +======= +We also can't change `Math.PI` to be `writable` again: -To be precise, non-configurability imposes several restrictions on `defineProperty`: -1. Can't change `configurable` flag. -2. Can't change `enumerable` flag. -3. Can't change `writable: false` to `true` (the other way round works). -4. Can't change `get/set` for an accessor property (but can assign them if absent). +```js run +// Error, because of configurable: false +Object.defineProperty(Math, "PI", { writable: true }); +``` +>>>>>>> 4d01fc20d4d82358e61518a31efe80dec9bb2602 -**The idea of "configurable: false" is to prevent changes of property flags and its deletion, while allowing to change its value.** +There's absolutely nothing we can do with `Math.PI`. + +Making a property non-configurable is a one-way road. We cannot change it back with `defineProperty`. + +**Please note: `configurable: false` prevents changes of property flags and its deletion, while allowing to change its value.** Here `user.name` is non-configurable, but we can still change it (as it's writable): >>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c @@ -301,7 +320,7 @@ user.name = "Pete"; // works fine delete user.name; // Error ``` -And here we make `user.name` a "forever sealed" constant: +And here we make `user.name` a "forever sealed" constant, just like the built-in `Math.PI`: ```js run let user = { @@ -335,11 +354,23 @@ delete user.name; Object.defineProperty(user, "name", { value: "Pete" }); ``` +<<<<<<< HEAD >>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c ## Object.defineProperties Bir vaqtning o'zida ko'plab xususiyatlarni aniqlashga imkon beradigan [Object.defineProperties(obj, descriptors)](mdn:js/Object/defineProperties) usuli mavjud. +======= +```smart header="The only attribute change possible: writable true -> false" +There's a minor exception about changing flags. + +We can change `writable: true` to `false` for a non-configurable property, thus preventing its value modification (to add another layer of protection). Not the other way around though. +``` + +## Object.defineProperties + +There's a method [Object.defineProperties(obj, descriptors)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties) that allows to define many properties at once. +>>>>>>> 4d01fc20d4d82358e61518a31efe80dec9bb2602 Sintaksis: @@ -365,7 +396,11 @@ Shunday qilib, biz bir vaqtning o'zida ko'plab xususiyatlarni o'rnatishimiz mumk ## Object.getOwnPropertyDescriptors +<<<<<<< HEAD Bir vaqtning o'zida barcha xususiyatlar tavsiflovchilarini olish uchun biz [Object.getOwnPropertyDescriptors(obj)](mdn:js/Object/getOwnPropertyDescriptors) usulidan foydalanishimiz mumkin. +======= +To get all property descriptors at once, we can use the method [Object.getOwnPropertyDescriptors(obj)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptors). +>>>>>>> 4d01fc20d4d82358e61518a31efe80dec9bb2602 `Object.defineProperties` bilan birgalikda u obyektni klonlashning "bayroqlardan xabardor" usuli sifatida ishlatilishi mumkin: @@ -391,6 +426,7 @@ Xususiyat tavsiflovchilari individual xususiyatlar darajasida ishlaydi. *Butun* obyektga kirishni cheklaydigan usullar ham mavjud: +<<<<<<< HEAD [Object.preventExtensions(obj)](mdn:js/Object/preventExtensions) : Obyektga yangi xususiyatlarni qo'shishni taqiqlaydi. @@ -402,11 +438,21 @@ Xususiyat tavsiflovchilari individual xususiyatlar darajasida ishlaydi. : Xususiyatlarni qo'shish/olib tashlash/o'zgartirishni taqiqlaydi. Mavjud barcha xususiyatlar uchun `configurable: false, writable: false` ni o'rnatadi. Va ular uchun testlar mavjud: ======= +======= +[Object.preventExtensions(obj)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/preventExtensions) +: Forbids the addition of new properties to the object. + +[Object.seal(obj)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/seal) +: Forbids adding/removing of properties. Sets `configurable: false` for all existing properties. + +[Object.freeze(obj)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze) +>>>>>>> 4d01fc20d4d82358e61518a31efe80dec9bb2602 : Forbids adding/removing/changing of properties. Sets `configurable: false, writable: false` for all existing properties. And also there are tests for them: >>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c +<<<<<<< HEAD [Object.isExtensible(obj)](mdn:js/Object/isExtensible) : Agar xususiyatlarni qo'shish taqiqlangan bo'lsa, `false` ni qaytaradi, aks holda `true`. @@ -415,5 +461,15 @@ And also there are tests for them: [Object.isFrozen(obj)](mdn:js/Object/isFrozen) : Xususiyatlarni qo'shish/olib tashlash/o'zgartirish taqiqlangan bo'lsa va barcha mavjud xususiyatlar `configurable: false, writable: false` bo'lsa, `true` ni qaytaradi. +======= +[Object.isExtensible(obj)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isExtensible) +: Returns `false` if adding properties is forbidden, otherwise `true`. + +[Object.isSealed(obj)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isSealed) +: Returns `true` if adding/removing properties is forbidden, and all existing properties have `configurable: false`. + +[Object.isFrozen(obj)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isFrozen) +: Returns `true` if adding/removing/changing properties is forbidden, and all current properties are `configurable: false, writable: false`. +>>>>>>> 4d01fc20d4d82358e61518a31efe80dec9bb2602 Ushbu usullar amalda kamdan kam qo'llaniladi. diff --git a/1-js/09-classes/04-private-protected-properties-methods/article.md b/1-js/09-classes/04-private-protected-properties-methods/article.md index bf0844004..8e48461f6 100644 --- a/1-js/09-classes/04-private-protected-properties-methods/article.md +++ b/1-js/09-classes/04-private-protected-properties-methods/article.md @@ -136,8 +136,13 @@ class CoffeeMachine { // kofe mashinasini yarating let coffeeMachine = new CoffeeMachine(100); +<<<<<<< HEAD // suv qo'shing coffeeMachine.waterAmount = -10; // Error: Salbiy suv +======= +// add water +coffeeMachine.waterAmount = -10; // _waterAmount will become 0, not -10 +>>>>>>> 4d01fc20d4d82358e61518a31efe80dec9bb2602 ``` <<<<<<< HEAD diff --git a/1-js/10-error-handling/2-custom-errors/article.md b/1-js/10-error-handling/2-custom-errors/article.md index b572b0149..91a69fe72 100644 --- a/1-js/10-error-handling/2-custom-errors/article.md +++ b/1-js/10-error-handling/2-custom-errors/article.md @@ -37,6 +37,7 @@ Bizning `readUser(json)` funktsiyasi nafaqat JSONni o'qiydi, balki ma'lumotlarni Bizning `ValidationError` klassi o'rnatilgan `Error` klassidan olinishi kerak. +<<<<<<< HEAD <<<<<<< HEAD Ushbu klass ichki o'rnatilgan, ammo biz nima kengaytirayotganimizni tushunish uchun uning taxminiy kodi bizning ko'z oldida bo'lishi kerak. @@ -44,6 +45,11 @@ Mana: ======= That class is built-in, but here's its approximate code so we can understand what we're extending: >>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c +======= +Our `ValidationError` class should inherit from the `Error` class. + +The `Error` class is built-in, but here's its approximate code so we can understand what we're extending: +>>>>>>> 4d01fc20d4d82358e61518a31efe80dec9bb2602 ```js // O'rnatilgan Xatolar sinfi uchun "pseudocode" JavaScript-ning o'zi tomonidan belgilanadi @@ -153,19 +159,27 @@ Quyidagi kabi `err.name` ga qarashimiz mumkin: // (err instanceof SyntaxError) ning o'rniga } else if (err.name == "SyntaxError") { // (*) // ... -``` +``` `instanceof` versiyasi ancha yaxshi, chunki kelajakda biz `ValidationError` ni kengaytiramiz, uning `TypeRequiredError` kabi pastki turlarini yaratamiz. Va `instanceof` tekshiruvi yangi meros klasslari uchun ishlashni davom ettiradi. Demak, bu kelajakka ishonchli. +<<<<<<< HEAD <<<<<<< HEAD Bundan tashqari, agar `catch` noma'lum xatoga duch kelsa, uni `(**)` satrida qayta tiklashi muhimdir. `catch` faqat tasdiqlash va sintaksis xatolarini qanday boshqarishni biladi, boshqa turlarni (koddagi xato yoki shunga o'xshash sabablarga ko'ra) boshqara ololmaydi. ======= Also it's important that if `catch` meets an unknown error, then it rethrows it in the line `(**)`. The `catch` block only knows how to handle validation and syntax errors, other kinds (due to a typo in the code or other unknown ones) should fall through. >>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c +======= +Also it's important that if `catch` meets an unknown error, then it rethrows it in the line `(**)`. The `catch` block only knows how to handle validation and syntax errors, other kinds (caused by a typo in the code or other unknown reasons) should fall through. +>>>>>>> 4d01fc20d4d82358e61518a31efe80dec9bb2602 ## Keyinchalik meros +<<<<<<< HEAD `ValidationError` klassi juda umumiy. Ko'p narsalar noto'g'ri ketishi mumkin. Xususiyat yo'q bo'lishi yoki noto'g'ri formatda bo'lishi mumkin (masalan, `age` uchun matn qiymati). Keling, aniq xususiyatlar uchun aniqroq `PropertyRequiredError` klassini yarataylik. Unda yetishmayotgan mulk to'g'risida qo'shimcha ma'lumotlar mavjud. +======= +The `ValidationError` class is very generic. Many things may go wrong. The property may be absent or it may be in a wrong format (like a string value for `age` instead of a number). Let's make a more concrete class `PropertyRequiredError`, exactly for absent properties. It will carry additional information about the property that's missing. +>>>>>>> 4d01fc20d4d82358e61518a31efe80dec9bb2602 ```js run class ValidationError extends Error { diff --git a/1-js/11-async/01-callbacks/article.md b/1-js/11-async/01-callbacks/article.md index 3b352bc39..c6563e45c 100644 --- a/1-js/11-async/01-callbacks/article.md +++ b/1-js/11-async/01-callbacks/article.md @@ -34,6 +34,7 @@ function loadScript(src) { } ``` +<<<<<<< HEAD <<<<<<< HEAD Funktsiyaning maqsadi yangi skriptni yuklashdir. Hujjatga ` diff --git a/2-ui/3-event-details/6-pointer-events/slider.view/style.css b/2-ui/3-event-details/6-pointer-events/slider.view/style.css index 9b3d3b82d..a84cd5e7e 100644 --- a/2-ui/3-event-details/6-pointer-events/slider.view/style.css +++ b/2-ui/3-event-details/6-pointer-events/slider.view/style.css @@ -8,6 +8,7 @@ } .thumb { + touch-action: none; width: 10px; height: 25px; border-radius: 3px; diff --git a/2-ui/3-event-details/7-keyboard-events/article.md b/2-ui/3-event-details/7-keyboard-events/article.md index 54bde42b4..51c1618f6 100644 --- a/2-ui/3-event-details/7-keyboard-events/article.md +++ b/2-ui/3-event-details/7-keyboard-events/article.md @@ -139,22 +139,25 @@ For instance, the `` below expects a phone number, so it does not accept ```html autorun height=60 run ``` -Please note that special keys, such as `key:Backspace`, `key:Left`, `key:Right`, `key:Ctrl+V`, do not work in the input. That's a side-effect of the strict filter `checkPhoneKey`. +The `onkeydown` handler here uses `checkPhoneKey` to check for the key pressed. If it's valid (from `0..9` or one of `+-()`), then it returns `true`, otherwise `false`. -Let's relax it a little bit: +As we know, the `false` value returned from the event handler, assigned using a DOM property or an attribute, such as above, prevents the default action, so nothing appears in the `` for keys that don't pass the test. (The `true` value returned doesn't affect anything, only returning `false` matters) +Please note that special keys, such as `key:Backspace`, `key:Left`, `key:Right`, do not work in the input. That's a side-effect of the strict filter `checkPhoneKey`. These keys make it return `false`. + +Let's relax the filter a little bit by allowing arrow keys `key:Left`, `key:Right` and `key:Delete`, `key:Backspace`: ```html autorun height=60 run @@ -162,7 +165,9 @@ function checkPhoneKey(key) { Now arrows and deletion works well. -...But we still can enter anything by using a mouse and right-click + Paste. So the filter is not 100% reliable. We can just let it be like that, because most of time it works. Or an alternative approach would be to track the `input` event -- it triggers after any modification. There we can check the new value and highlight/modify it when it's invalid. +Even though we have the key filter, one still can enter anything using a mouse and right-click + Paste. Mobile devices provide other means to enter values. So the filter is not 100% reliable. + +The alternative approach would be to track the `oninput` event -- it triggers *after* any modification. There we can check the new `input.value` and modify it/highlight the `` when it's invalid. Or we can use both event handlers together. ## Legacy diff --git a/2-ui/4-forms-controls/3-events-change-input/1-deposit-calculator/solution.view/index.html b/2-ui/4-forms-controls/3-events-change-input/1-deposit-calculator/solution.view/index.html index 4850b2ca9..0515c839e 100644 --- a/2-ui/4-forms-controls/3-events-change-input/1-deposit-calculator/solution.view/index.html +++ b/2-ui/4-forms-controls/3-events-change-input/1-deposit-calculator/solution.view/index.html @@ -96,7 +96,7 @@ let years = form.months.value / 12; if (!years) return; - let result = Math.round(initial * (1 + interest * years)); + let result = Math.round(initial * (1 + interest) ** years); let height = result / form.money.value * 100 + 'px'; document.getElementById('height-after').style.height = height; diff --git a/2-ui/4-forms-controls/3-events-change-input/1-deposit-calculator/task.md b/2-ui/4-forms-controls/3-events-change-input/1-deposit-calculator/task.md index e324577a9..73f0477ff 100644 --- a/2-ui/4-forms-controls/3-events-change-input/1-deposit-calculator/task.md +++ b/2-ui/4-forms-controls/3-events-change-input/1-deposit-calculator/task.md @@ -17,5 +17,5 @@ The formula is: // initial: the initial money sum // interest: e.g. 0.05 means 5% per year // years: how many years to wait -let result = Math.round(initial * (1 + interest * years)); +let result = Math.round(initial * (1 + interest) ** years); ``` diff --git a/2-ui/4-forms-controls/3-events-change-input/article.md b/2-ui/4-forms-controls/3-events-change-input/article.md index 1355e8bb6..6865e2a40 100644 --- a/2-ui/4-forms-controls/3-events-change-input/article.md +++ b/2-ui/4-forms-controls/3-events-change-input/article.md @@ -76,7 +76,7 @@ For instance, the code below prevents all such events and shows what we are tryi Please note, that it's possible to copy/paste not just text, but everything. For instance, we can copy a file in the OS file manager, and paste it. -That's because `clipboardData` implements `DataTransfer` interface, commonly used for drag'n'drop and copy/pasting. It's bit beyound our scope now, but you can find its methods [in the specification](https://html.spec.whatwg.org/multipage/dnd.html#the-datatransfer-interface). +That's because `clipboardData` implements `DataTransfer` interface, commonly used for drag'n'drop and copy/pasting. It's bit beyond our scope now, but you can find its methods [in the specification](https://html.spec.whatwg.org/multipage/dnd.html#the-datatransfer-interface). ```warn header="ClipboardAPI: user safety restrictions" The clipboard is a "global" OS-level thing. So most browsers allow read/write access to the clipboard only in the scope of certain user actions for the safety, e.g. in `onclick` event handlers. diff --git a/2-ui/5-loading/01-onload-ondomcontentloaded/article.md b/2-ui/5-loading/01-onload-ondomcontentloaded/article.md index 9cc9fc7c5..cd9267421 100644 --- a/2-ui/5-loading/01-onload-ondomcontentloaded/article.md +++ b/2-ui/5-loading/01-onload-ondomcontentloaded/article.md @@ -2,7 +2,7 @@ The lifecycle of an HTML page has three important events: -- `DOMContentLoaded` -- the browser fully loaded HTML, and the DOM tree is built, but external resources like pictures `` and stylesheets may not yet have loaded. +- `DOMContentLoaded` -- the browser fully loaded HTML, and the DOM tree is built, but external resources like pictures `` and stylesheets may not yet have loaded. - `load` -- not only HTML is loaded, but also all the external resources: images, styles etc. - `beforeunload/unload` -- the user is leaving the page. @@ -114,7 +114,7 @@ The example below correctly shows image sizes, because `window.onload` waits for ```html run height=200 refresh +``` + +Here's a more complex example, with `@keyframes`: + +```html run height=80 autorun no-beautify +

click me to start / stop

+ +``` + ## Summary -CSS animations allow smoothly (or not) animated changes of one or multiple CSS properties. +CSS animations allow smoothly (or step-by-step) animated changes of one or multiple CSS properties. They are good for most animation tasks. We're also able to use JavaScript for animations, the next chapter is devoted to that. @@ -422,6 +503,8 @@ Limitations of CSS animations compared to JavaScript animations: - Not just property changes. We can create new elements in JavaScript as part of the animation. ``` +In early examples in this chapter, we animate `font-size`, `left`, `width`, `height`, etc. In real life projects, we should use `transform: scale()` and `transform: translate()` for better performance. + The majority of animations can be implemented using CSS as described in this chapter. And the `transitionend` event allows JavaScript to be run after the animation, so it integrates fine with the code. But in the next chapter we'll do some JavaScript animations to cover more complex cases. diff --git a/8-web-components/1-webcomponents-intro/article.md b/8-web-components/1-webcomponents-intro/article.md index 3279cb133..c3522dea9 100644 --- a/8-web-components/1-webcomponents-intro/article.md +++ b/8-web-components/1-webcomponents-intro/article.md @@ -26,9 +26,9 @@ The International Space Station: ...And this thing flies, keeps humans alive in space! -How such complex devices are created? +How are such complex devices created? -Which principles we could borrow to make our development same-level reliable and scalable? Or, at least, close to it. +Which principles could we borrow to make our development same-level reliable and scalable? Or, at least, close to it? ## Component architecture diff --git a/figures.sketch b/figures.sketch index aa3ecfcab..88f3d19cb 100644 Binary files a/figures.sketch and b/figures.sketch differ