diff --git a/1-js/01-getting-started/1-intro/article.md b/1-js/01-getting-started/1-intro/article.md index c048430b3..49a56c66e 100644 --- a/1-js/01-getting-started/1-intro/article.md +++ b/1-js/01-getting-started/1-intro/article.md @@ -29,7 +29,13 @@ من الجيد تذكر المصطلحات الواردة أعلاه لأنها مستخدمة في مقالات المطورين على الإنترنت. سنستخدمهم أيضًا. على سبيل المثال ، إذا كانت "الميزة إكس مدعومة بواسطة في8" ، فمن المحتمل أنها تعمل في كروم و أوبرا. +<<<<<<< HEAD ```smart header="كيف تعمل المحركات؟" +======= +- [V8](https://en.wikipedia.org/wiki/V8_(JavaScript_engine)) -- in Chrome and Opera. +- [SpiderMonkey](https://en.wikipedia.org/wiki/SpiderMonkey) -- in Firefox. +- ...There are other codenames like "Chakra" for IE, "JavaScriptCore", "Nitro" and "SquirrelFish" for Safari, etc. +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c المحركات معقدة. ولكن الأساسيات بسيطه . diff --git a/1-js/01-getting-started/4-devtools/article.md b/1-js/01-getting-started/4-devtools/article.md index 3dded1566..22aa85b22 100644 --- a/1-js/01-getting-started/4-devtools/article.md +++ b/1-js/01-getting-started/4-devtools/article.md @@ -8,7 +8,11 @@ يفضل معظم المطورون العمل على متصفِّحي Chrome أو FireFox لاحتوائهما على أفضل أدوات المطوّر. توفر المتصفِّحات الأخرى أيضًا مجموعة أدوات للمطوّر والتي من الممكن أن تحتوي على مزايا خاصة. لكن عادةً ما تحاول اللحاق بمتصفِّحي Chrome و FireFox الأفضل من هذه الناحية. يفضل المطوّرون بشكل عام العمل على متصفِّح واحد وينتقلون إلى متصفِّح آخر عندما تكون المشكلة التي يعملون عليها محدَّدة بهذا المتصفِّح. +<<<<<<< HEAD بناءً على ذلك، نجد أنَّ أدوات المطور مهمة للغاية لما تمتلكه من مزايا تساعدك أثناء مسيرتك في تطوير الويب عبر JavaScript. سنتعلم في البداية طريقة فتحها، واستخدامها لاستكشاف الأخطاء، وتشغيل تعليمات JavaScript ضمنها. +======= +Developer tools are potent; they have many features. To start, we'll learn how to open them, look at errors, and run JavaScript commands. +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c أدوات المطور قوية, لديها العديد من الميزات. للبدء, سنتعلم كيفية فتحها ، والنظر في الأخطاء ، وتشغيل أوامر جافا سكريبت. diff --git a/1-js/02-first-steps/02-structure/article.md b/1-js/02-first-steps/02-structure/article.md index 6285c198d..c2388fbfa 100644 --- a/1-js/02-first-steps/02-structure/article.md +++ b/1-js/02-first-steps/02-structure/article.md @@ -46,6 +46,7 @@ alert(3+ قريبًا خلال الشيفرات التي ستكتبها). إذا كنت ترغب في الاطلاع على مثال واقعي عن هذه الحالة، إليك الشيفرة البرمجية التالية: +<<<<<<< HEAD ``` [1, 2].foreach(alert) ``` @@ -55,10 +56,36 @@ alert(3+ ``` alert("There will be an error") [1 ,2].forEach(alert) +======= +The code outputs `6` because JavaScript does not insert semicolons here. It is intuitively obvious that if the line ends with a plus `"+"`, then it is an "incomplete expression", so a semicolon there would be incorrect. And in this case, that works as intended. + +**But there are situations where JavaScript "fails" to assume a semicolon where it is really needed.** + +Errors which occur in such cases are quite hard to find and fix. + +````smart header="An example of an error" +If you're curious to see a concrete example of such an error, check this code out: + +```js run +alert("Hello"); + +[1, 2].forEach(alert); +``` + +No need to think about the meaning of the brackets `[]` and `forEach` yet. We'll study them later. For now, just remember the result of running the code: it shows `Hello`, then `1`, then `2`. + +Now let's remove the semicolon after the `alert`: + +```js run no-beautify +alert("Hello") + +[1, 2].forEach(alert); +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c ``` عند تنفيذ الشيفرة البرمجية آنذاك، سيتم إظهار التنبيه الأول فقط ثم سنحصل على خطأ. تعود الشيفرة البرمجية للعمل بشكل صحيح مرة أخرى عند إضافة الفاصلة المنقوطة بعد التنبيه الأول: +<<<<<<< HEAD ``` alert("All fine now"); [1 ,2].forEach(alert) @@ -72,6 +99,18 @@ alert("All fine now"); ``` alert("There will be an error")[1, 2].forEach(alert) +======= +The difference compared to the code above is only one character: the semicolon at the end of the first line is gone. + +If we run this code, only the first `Hello` shows (and there's an error, you may need to open the console to see it). There are no numbers any more. + +That's because JavaScript does not assume a semicolon before square brackets `[...]`. So, the code in the last example is treated as a single statement. + +Here's how the engine sees it: + +```js run no-beautify +alert("Hello")[1, 2].forEach(alert); +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c ``` ولكنهما عبارتين برمجيتين منفصلتين وليستا عبارة واحدة، وبالتالي عملية الدمج في هذه الحالة خطأ. من الممكن أن تتكرر هذه الحالة ضمن شروط أخرى. @@ -87,7 +126,24 @@ alert("There will be an error")[1, 2].forEach(alert) المائلين على نفس السطر تعليقًا. ومن الممكن أن يشغل التعليق سطرًا كاملًا أو يأتي التعليق بعد العبارة البرمجية. إليك المثال التالي الذي يشرح ما سبق: +<<<<<<< HEAD ``` +======= +Looks weird, right? Such merging in this case is just wrong. We need to put a semicolon after `alert` for the code to work correctly. + +This can happen in other situations also. +```` + +We recommend putting semicolons between statements even if they are separated by newlines. This rule is widely adopted by the community. Let's note once again -- *it is possible* to leave out semicolons most of the time. But it's safer -- especially for a beginner -- to use them. + +## Comments [#code-comments] + +As time goes on, programs become more and more complex. It becomes necessary to add *comments* which describe what the code does and why. + +Comments can be put into any place of a script. They don't affect its execution because the engine simply ignores them. + +**One-line comments start with two forward slash characters `//`.** +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c // يمتد هذا التعليق على كامل السطر فقط diff --git a/1-js/02-first-steps/05-types/article.md b/1-js/02-first-steps/05-types/article.md index d555a8c24..14efde718 100644 --- a/1-js/02-first-steps/05-types/article.md +++ b/1-js/02-first-steps/05-types/article.md @@ -65,7 +65,7 @@ n = 12.345; سنرى المزيد من التعامل مع الأرقام خلال هذا الفصل . -## BigInt +## BigInt [#bigint-type] في جافا سكريبت، النوع "number" لا يمثل الأعداد الصحيحة أكبر من (253-1) (و هو `9007199254740991`)، أو أقل من -(-253-1) للأرقام السالبة. إنها قيود فنية ناتجة عن تمثيلهم الداخلي. diff --git a/1-js/02-first-steps/08-operators/article.md b/1-js/02-first-steps/08-operators/article.md index f3b7469c2..914ffd772 100644 --- a/1-js/02-first-steps/08-operators/article.md +++ b/1-js/02-first-steps/08-operators/article.md @@ -56,18 +56,30 @@ alert( 8 % 3 ); // 2, a remainder of 8 divided by 3 ### الضرب الأسي ** +<<<<<<< HEAD عامل الضرب الأسي `a ** b` يقوم بضرب الرقم `a` في نفسه عدد `b` من المرات +======= +The exponentiation operator `a ** b` raises `a` to the power of `b`. + +In school maths, we write that as ab. +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c على سبيل المثال: ```js run -alert( 2 ** 2 ); // 4 (2 multiplied by itself 2 times) -alert( 2 ** 3 ); // 8 (2 * 2 * 2, 3 times) -alert( 2 ** 4 ); // 16 (2 * 2 * 2 * 2, 4 times) +alert( 2 ** 2 ); // 2² = 4 +alert( 2 ** 3 ); // 2³ = 8 +alert( 2 ** 4 ); // 2⁴ = 16 ``` +<<<<<<< HEAD من الناحية الرياضياتية الضرب الأسي يستخدم أيضا مع الأرقام غير الصحيحة. على سبيل المثال الجذر التربيعي هو ضرب أسي بقيمة `1/2`: +======= +Just like in maths, the exponentiation operator is defined for non-integer numbers as well. + +For example, a square root is an exponentiation by ½: +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c ```js run alert( 4 ** (1/2) ); // 2 (power of 1/2 is the same as a square root) 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 3dd3a9db0..834aa246f 100644 --- a/1-js/02-first-steps/13-while-for/article.md +++ b/1-js/02-first-steps/13-while-for/article.md @@ -377,9 +377,24 @@ break label; // تنتقل إلى الحقل بالأسفل (لا تعمل) label: for (...) ``` +<<<<<<< HEAD إستخدام `continue` يكون ممكنًا فقط من داخل الحلقه. `break` ربما يمكن وضعه قبل الشيفرة ايضًا, as `label: { ... }`, لكنها لا تستخدم أبدًا بهذه الطريقة. وهي تعمل أيضًا من الداخل إلى الخارج فقط. +======= +A `break` directive must be inside a code block. Technically, any labelled code block will do, e.g.: +```js +label: { + // ... + break label; // works + // ... +} +``` + +...Although, 99.9% of the time `break` used is inside loops, as we've seen in the examples above. + +A `continue` is only possible from inside a loop. +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c ```` ## ملخص diff --git a/1-js/02-first-steps/15-function-basics/2-rewrite-function-question-or/solution.md b/1-js/02-first-steps/15-function-basics/2-rewrite-function-question-or/solution.md index 191d03c97..d9e9a3f7a 100644 --- a/1-js/02-first-steps/15-function-basics/2-rewrite-function-question-or/solution.md +++ b/1-js/02-first-steps/15-function-basics/2-rewrite-function-question-or/solution.md @@ -14,4 +14,8 @@ function checkAge(age) { } ``` +<<<<<<< HEAD لاحظ أن الأقواس حول `age > 18` غير مطلوبة ولكن تم وضعها لزيادة القدرة على قراءة الكود. +======= +Note that the parentheses around `age > 18` are not required here. They exist for better readability. +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c 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 0c7b690e3..0e6e9b82c 100644 --- a/1-js/02-first-steps/15-function-basics/article.md +++ b/1-js/02-first-steps/15-function-basics/article.md @@ -20,10 +20,14 @@ function showMessage() { } ``` +<<<<<<< HEAD كلمة `function` تكتب أولا ثم يكتب _اسم الدالة_ ثم قائمة _parameters_ بين القوسين (يفصل بينهم بفاصلة وهي فارغة في المثال السابق) وأخيرا الكود الذي ينفذ ويسمى "the function body" بين القوسين المعقوفين. +======= +The `function` keyword goes first, then goes the *name of the function*, then a list of *parameters* between the parentheses (comma-separated, empty in the example above, we'll see examples later) and finally the code of the function, also named "the function body", between curly braces. +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c ```js -function name(parameters) { +function name(parameter1, parameter2, ... parameterN) { ...body... } ``` @@ -137,25 +141,30 @@ alert( userName ); // *!*John*/!*, لم يتغير, الدالة لن تصل ل ## Parameters +<<<<<<< HEAD يمكننا تمرير أي قيم إلى الدالة باستخدام parameters (أيضًا تسمى _function arguments_) . +======= +We can pass arbitrary data to functions using parameters. +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c في هذا المثال الدالة لديها معاملين: `from` و `text`. ```js run -function showMessage(*!*from, text*/!*) { // arguments: from, text +function showMessage(*!*from, text*/!*) { // parameters: from, text alert(from + ': ' + text); } -*!* -showMessage('Ann', 'Hello!'); // Ann: Hello! (*) -showMessage('Ann', "What's up?"); // Ann: What's up? (**) -*/!* +*!*showMessage('Ann', 'Hello!');*/!* // Ann: Hello! (*) +*!*showMessage('Ann', "What's up?");*/!* // Ann: What's up? (**) ``` عند استدعاء الدالة في السطر `(*)` و `(**)` فإن القيم الممررة تنسخ إلى المتغيرات المحلية `from` و `text`. ثم تقوم الدالة باستخدامهم. +<<<<<<< HEAD هنا مثال آخر حيث لدينا المتغير `from` وقمنا بتمريره إلى الدالة. لاحظ أن الدالة قامت بتغيير قيمة `from` ولكن التغيير لا يؤثر في المتغير الممرر لأن الدالة تحصل على نسخة من القيمة: +======= +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c ```js run function showMessage(from, text) { @@ -174,9 +183,27 @@ showMessage(from, "Hello"); // *Ann*: Hello alert( from ); // Ann ``` +<<<<<<< HEAD ## القيم الإفتراضية إذا لم يتم تمرير قيمة Parameter يأخذ القيمة `undefined`. +======= +When a value is passed as a function parameter, it's also called an *argument*. + +In other words, to put these terms straight: + +- A parameter is the variable listed inside the parentheses in the function declaration (it's a declaration time term) +- An argument is the value that is passed to the function when it is called (it's a call time term). + +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"`". + + +## Default values + +If a function is called, but an argument is not provided, then the corresponding value becomes `undefined`. +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c على سبيل المثال الفنكشن السابقة `showMessage(from, text)` يمكن استدعائها وتمرير قيمة واحدة فقط: @@ -184,9 +211,15 @@ alert( from ); // Ann showMessage("Ann"); ``` +<<<<<<< HEAD هذا ليس خطأ ولكن سينتج `"Ann: undefined"`. لم يتم تمرير `text` لذلك يتم افتراض أن `text === undefined`. إذا أردت تخصيص قيمة إفتراضية ل `text` يمكن وضعها بعد `=`: +======= +That's not an error. Such a call would output `"*Ann*: undefined"`. As the value for `text` isn't passed, it becomes `undefined`. + +We can specify the so-called "default" (to use if omitted) value for a parameter in the function declaration, using `=`: +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c ```js run function showMessage(from, *!*text = "no text given"*/!*) { @@ -210,19 +243,33 @@ function showMessage(from, text = anotherFunction()) { ```smart header="تنفيذ القيم الإفتراضية" في جافا سكريبت يتم تنفيذ القيم الإفتراضية في كل مرة يتم استدعاء الدالة دون تمرير قيمة. +<<<<<<< HEAD في المثال السابق سيتم تنفيذ `anotherFunction()` في كل مرة يتم استدعا `showMessage()` دون تمرير قيمة `text`. +======= +In the example above, `anotherFunction()` isn't called at all, if the `text` parameter is provided. + +On the other hand, it's independently called every time when `text` is missing. +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c ``` ### بديل القيم الإفتراضية +<<<<<<< HEAD أحيانا نريدتحديد قيمة لإفتراضية ولكن ليس في تعريف الدالة بل في وقت لاحق أثناء التنفيذ. لمعرفة المتغير الذي لم يمرر قيمته يمكننا مقارنته مع `undefined`: +======= +Sometimes it makes sense to assign default values for parameters not in the function declaration, but at a later stage. + +We can check if the parameter is passed during the function execution, by comparing it with `undefined`: +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c ```js run function showMessage(text) { + // ... + *!* - if (text === undefined) { + if (text === undefined) { // if the parameter is missing text = 'empty message'; } */!* @@ -233,22 +280,38 @@ function showMessage(text) { showMessage(); // empty message ``` +<<<<<<< HEAD ...أو نستخدم العامل `||`: ```js // إذا لم يتم تمرير قيمة text أو تم تمرير "" يجعل قيمته 'empty' +======= +...Or we could use the `??` operator: + +```js +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c function showMessage(text) { + // if text is undefined or otherwise falsy, set it to 'empty' text = text || 'empty'; ... } ``` +<<<<<<< HEAD محركات جافا سكريبت الحديثة تدعم [nullish coalescing operator](info:nullish-coalescing-operator) `??`وهوأفضل في التعامل مع falsy values مثل `0`: ```js run // إذا لم يوجد قيمة "count" يعرض "unknown" function showCount(count) { alert(count ?? "unknown"); +======= +Modern JavaScript engines support the [nullish coalescing operator](info:nullish-coalescing-operator) `??`, it's better when most falsy values, such as `0`, should be considered "normal": + +```js run +function showCount(count) { + // if count is undefined or null, show "unknown" + alert(count ?? "unknown"); +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c } showCount(0); // 0 @@ -413,7 +476,11 @@ checkPermission(..) // checks a permission, returns true/false على سبيل المثال مكتبة [jQuery](http://jquery.com) تعرف دالة اسمها `$`. ومكتبة [Lodash](http://lodash.com/) لديها دالة اسمها `_`. +<<<<<<< HEAD هذه مجرد استثناءات ففي العموم يجب أن يكون اسم الدالة معبرًا. +======= +These are exceptions. Generally function names should be concise and descriptive. +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c ``` ## الدوال == تعليقات diff --git a/1-js/02-first-steps/17-arrow-functions-basics/1-rewrite-arrow/solution.md b/1-js/02-first-steps/17-arrow-functions-basics/1-rewrite-arrow/solution.md index 935ed23f8..516d76cec 100644 --- a/1-js/02-first-steps/17-arrow-functions-basics/1-rewrite-arrow/solution.md +++ b/1-js/02-first-steps/17-arrow-functions-basics/1-rewrite-arrow/solution.md @@ -1,6 +1,6 @@ ```js run function ask(question, yes, no) { - if (confirm(question)) yes() + if (confirm(question)) yes(); else no(); } diff --git a/1-js/02-first-steps/17-arrow-functions-basics/1-rewrite-arrow/task.md b/1-js/02-first-steps/17-arrow-functions-basics/1-rewrite-arrow/task.md index ef8576c11..83ceade90 100644 --- a/1-js/02-first-steps/17-arrow-functions-basics/1-rewrite-arrow/task.md +++ b/1-js/02-first-steps/17-arrow-functions-basics/1-rewrite-arrow/task.md @@ -4,8 +4,13 @@ ```js run function ask(question, yes, no) { +<<<<<<< HEAD if (confirm(question)) yes(); else no(); +======= + if (confirm(question)) yes(); + else no(); +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c } ask( diff --git a/1-js/03-code-quality/01-debugging-chrome/article.md b/1-js/03-code-quality/01-debugging-chrome/article.md index 1f969765a..cd668f5c5 100644 --- a/1-js/03-code-quality/01-debugging-chrome/article.md +++ b/1-js/03-code-quality/01-debugging-chrome/article.md @@ -1,4 +1,8 @@ +<<<<<<< HEAD # تصحيح الأخطاء في كروم +======= +# Debugging in the browser +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c قبل كتابة أي كود معقد , فلنتحدث قليلا عن تصحيح الأخطاء. diff --git a/1-js/03-code-quality/05-testing-mocha/article.md b/1-js/03-code-quality/05-testing-mocha/article.md index 7e0885492..8ca1240f4 100644 --- a/1-js/03-code-quality/05-testing-mocha/article.md +++ b/1-js/03-code-quality/05-testing-mocha/article.md @@ -2,7 +2,11 @@ يُستخدَم الاختبار الآلي في الكثير من المهام، كما يستخدم بكثرة في المشاريع الحقيقية. +<<<<<<< HEAD ## لم نحتاج الاختبارات؟ +======= +## Why do we need tests? +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c عند كتابة دالة، يمكننا تخيل ما يجب أن تقوم به: ما هي المعاملات التي تعطي نتائج معينة. يمكننا فحص الدالة أثناء التطوير من خلال تشغيلها وموازنة مخرجاتها مع ما هو متوقع. مثلا يمكننا القيام بذلك في الطرفية. diff --git a/1-js/03-code-quality/06-polyfills/article.md b/1-js/03-code-quality/06-polyfills/article.md index 9b86c4f36..1b4c0b5e1 100644 --- a/1-js/03-code-quality/06-polyfills/article.md +++ b/1-js/03-code-quality/06-polyfills/article.md @@ -47,7 +47,7 @@ Modern project build systems, such as [webpack](http://webpack.github.io/), prov New language features may include not only syntax constructs and operators, but also built-in functions. -For example, `Math.trunc(n)` is a function that "cuts off" the decimal part of a number, e.g `Math.trunc(1.23) = 1`. +For example, `Math.trunc(n)` is a function that "cuts off" the decimal part of a number, e.g `Math.trunc(1.23)` returns `1`. In some (very outdated) JavaScript engines, there's no `Math.trunc`, so such code will fail. diff --git a/1-js/04-object-basics/04-object-methods/article.md b/1-js/04-object-basics/04-object-methods/article.md index acbb2e8b8..f00aedd59 100644 --- a/1-js/04-object-basics/04-object-methods/article.md +++ b/1-js/04-object-basics/04-object-methods/article.md @@ -80,7 +80,7 @@ user = { // يبدو شكل الدالة المختصر أفضل، أليس كذلك؟ user = { *!* - sayHi() { // same as "sayHi: function()" + sayHi() { // same as "sayHi: function(){...}" */!* alert("Hello"); } diff --git a/1-js/04-object-basics/06-constructor-new/article.md b/1-js/04-object-basics/06-constructor-new/article.md index 6c0fa9039..b1c2885f1 100644 --- a/1-js/04-object-basics/06-constructor-new/article.md +++ b/1-js/04-object-basics/06-constructor-new/article.md @@ -55,6 +55,7 @@ isAdmin: false لاحظ أنَّه يمكن استخدام أي دالة لتكون دالة بانية تقنيًا. يعني أنه يمكن تنفيذ أي دالة مع `new`، وستُنَفَّذ باستخدام الخوارزمية أعلاه. استخدام الأحرف الكبيرة في البداية هو اتفاق شائع لتمييز الدالة البانية من غيرها وأنَّه يجب استدعاؤها مع `new`. +<<<<<<< HEAD ### `**new function() { … }‎**` إن كان لدينا العديد من الأسطر البرمجية، وجميعها عن إنشاء كائن واحد مُعَقَّد، فبإمكاننا تضمينها في دالة بانية، هكذا: @@ -70,6 +71,27 @@ this.isAdmin = false; ``` لا يمكن استدعاء المُنشِئ مجددًا، لأنه غير محفوظ في أي مكان، يُنشَأ ويُستدعى فقط. لذا فإن الخدعة تهدف إلى تضمين الشيفرة التي تُنشِئ كائنًا واحدًا، دون إعادة الاستخدام وتكرار العملية مستقبلًا. +======= +Let's note once again -- technically, any function (except arrow functions, as they don't have `this`) can be used as a constructor. It can be run with `new`, and it will execute the algorithm above. The "capital letter first" is a common agreement, to make it clear that a function is to be run with `new`. + +````smart header="new function() { ... }" +If we have many lines of code all about creation of a single complex object, we can wrap them in an immediately called constructor function, like this: + +```js +// create a function and immediately call it with new +let user = new function() { + this.name = "John"; + this.isAdmin = false; + + // ...other code for user creation + // maybe complex logic and statements + // local variables etc +}; +``` + +This constructor can't be called again, because it is not saved anywhere, just created and called. So this trick aims to encapsulate the code that constructs the single object, without future reuse. +```` +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c ## وضع اختبار الباني: `new.target` diff --git a/1-js/04-object-basics/09-object-toprimitive/article.md b/1-js/04-object-basics/09-object-toprimitive/article.md index 2ad596136..0eb2ac55b 100644 --- a/1-js/04-object-basics/09-object-toprimitive/article.md +++ b/1-js/04-object-basics/09-object-toprimitive/article.md @@ -4,7 +4,28 @@ فى هذه الحالة، تتحول الكائنات إلى قيم فردية تلقائيًا، ثم يتم تنفيذ هذه العملية الحسابية. +<<<<<<< HEAD فى قسم (تحويل الأنواع) رأينا كيف يمكن تحويل النصوص (strings) والأرقام والقيَم المنطقيه (booleans) إلى قيم فردية. ولكننا تركنا مساحة فارغة من أجل الكائنات. والآن بعد أن عرفنا الكثير عن الدوال (methods) والرموز (symbols)، أصبح الآن ممكنًا أن نملأ هذه المساحه. +======= +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 archievements 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 +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c 1. كل الكائنات عند تحويلها إلى قيمه منطقيه (boolean) فإن قيمتها تساوى `true`. وبالتالى فإن التحويلات المتاحة هي التحويل إلى نص أو رقم. @@ -12,6 +33,7 @@ 3. وبالنسبه إلى التحويل إلى نص -- فإنه يحدث عادة عند طباعة الكائن باستخدام دالة التنبيه `alert(obj)` والدوال المشابهة. +<<<<<<< HEAD ## ToPrimitive يمكننا التحكم فى التحويل إلى نص أو رقم، باستخدام بعض دوال الكائنات. @@ -19,6 +41,13 @@ هناك ثلاث ملاحظات مختلفه على تحويل الأنواع ويطلق عليها "hints" وتم ذكرها فى [المصدر](https://tc39.github.io/ecma262/#sec-toprimitive): `"النص"` +======= +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): +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c : يحدث التحويل إلى نص عندما نقوم بعملية معينه على كائن تتوقع نصًا لا كائنًا مثل دالة التنبيه `alert`: @@ -87,12 +116,19 @@ if (user == 1) { ... }; ```js obj[Symbol.toPrimitive] = function(hint) { - // must return a primitive value + // here goes the code to convert this object to a primitive + // it must return a primitive value // hint = one of "string", "number", "default" }; ```` +<<<<<<< HEAD على سبيل المثال, يطبق هذه الطريقه الكائن `user`: +======= +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: +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c ```js run let user = { @@ -115,12 +151,21 @@ alert(user + 500); // hint: default -> 1500 ## toString/valueOf +<<<<<<< HEAD الدوال `toString` و `valueOf`موجوده من قديم الأزل. إنهم ليسو رموزًا ولكنهم دوال تستعمل مع النصوص. ويقومون بتوفير طريقة قديمه للقيام بالتحويل. إذا لم يكن هناك `Symbol.toPrimitive` فإن جافا سكريبت تقوم بالبحث عنهمو استخدامهم بالترتيب الآتى: - `toString -> valueOf` فى الطريقه النصيه. - `valueOf -> toString` غير ذلك. +======= +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 stirng 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. +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c هذه الدوال لابد أن تقوم بإرجاع قيمه فردية. فإذا قامت هاتان الدالتان بإرجاع كائن فسيتم تجاهله. @@ -140,9 +185,15 @@ alert(user.valueOf() === user); // true لذلك إذا حاولنا أن نستخدم الكائن كنص، كما فى حالة استخدام الداله النصيه `alert` سنرى بشكل افتراضي `[object object]`. +<<<<<<< HEAD الداله `valueOf` تم ذكرها هنا فقط لإكمال المعلومات ولتجنب أى التباس. فكما ترى فإن هذه الداله تقوم بإرجاع الكائن نفسه وبالتالى يتم تجاهله. لا تسأل لماذا فهذا لأسباب متأصله historical reasons. ولذلك يمكننا اعتبار أنها غير موجوده. هيا نقوم باستخدام هذه الدوال. +======= +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. +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c على سبيل المثال، فإن الكائن `user` هنا يقوم بنفس التصرف أعلاه عند استخدام خليط من `toString` و `valueOf` بدلًا من `Symbol.toPrimitive`: @@ -186,7 +237,11 @@ alert(user + 500); // toString -> John500 فى حالة غياب `Symbol.toPrimitive` و `valueOf` فإن `toString` ستقوم بالتعامل مع كل حالات التحويل إلى قيم فرديه. +<<<<<<< HEAD ## أنواع القيم المسترجعه +======= +### A conversion can return any primitive type +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c هناك شئ مهم يجب أن تعرفه وهو أن كل طرق التحويل إلى قيم مفرده لا يجب بالضروره أن تقوم بإرجاع نفس نوع القيمه المفرده المحوَّله إليه. @@ -261,4 +316,10 @@ alert(obj + 2); // 22 ("2" + 2), conversion to primitive returned a string => co 3. غير ذلك إذا كانت الطريقة `"رقمًا"` أو `"الطريقة الإفتراضيه"` - استخدام `obj.valueOf()` أو `obj.toString()` فى حالة وجود أى منهم. +<<<<<<< HEAD ويكفى عمليًا استخدام `obj.toString()` لكل التحويلات والتى تقوم بإرجاع قيمة يمكن قرائتها من أجل الطباعة أو البحث عن الأخطاء. +======= +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. +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c diff --git a/1-js/05-data-types/01-primitives-methods/article.md b/1-js/05-data-types/01-primitives-methods/article.md index 7c7671d2d..d6820786d 100644 --- a/1-js/05-data-types/01-primitives-methods/article.md +++ b/1-js/05-data-types/01-primitives-methods/article.md @@ -40,8 +40,13 @@ Objects "اثقل" من الأساليب البدائية. وهي تتطلب م هنا التناقض الذي واجه صانع جافا سكريبت: +<<<<<<< HEAD - هناك العديد من الأشياء التي يمكن أن يفعلها الشخص بالأسلوب البدائي مثل string أو number. سيكون من الرائع استخدامهم كا methods. - الأساليب البدائية يجب أن تكون سريعة وخفيفة بقدر الإمكان. +======= +- There are many things one would want to do with a primitive like a string or a number. It would be great to access them using methods. +- Primitives must be as fast and lightweight as possible. +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c إن الحل يبدو غريبا بعض الشيء، ولكن ها هو: diff --git a/1-js/05-data-types/03-string/article.md b/1-js/05-data-types/03-string/article.md index e83e5aa67..9ce7f79de 100644 --- a/1-js/05-data-types/03-string/article.md +++ b/1-js/05-data-types/03-string/article.md @@ -532,7 +532,12 @@ alert( str ); - تأتي الأحرف الصغيرة بعد الأحرف الكبيرة دائمًا لأن رموزها العددية دائمًا أكبر. - تكون بعض الأحرف مثل `Ö` بعيدة عن الأحرف الهجائية. هنا، قيمة الحرف هذا أكبر من أي حرف بين `a` و `z`. +<<<<<<< HEAD ### موازنات صحيحة +======= +- All lowercase letters go after uppercase letters because their codes are greater. +- Some letters like `Ö` stand apart from the main alphabet. Here, its code is greater than anything from `a` to `z`. +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c ### Correct comparisons [#correct-comparisons] diff --git a/1-js/05-data-types/04-array/article.md b/1-js/05-data-types/04-array/article.md index 29a027ded..6a3baeaa9 100644 --- a/1-js/05-data-types/04-array/article.md +++ b/1-js/05-data-types/04-array/article.md @@ -371,9 +371,13 @@ alert( arr[0] ); // غير معرف! لا توجد عناصر. alert( arr.length ); // الطول 2 ``` +<<<<<<< HEAD في الكود أعلاه, `مصفوفه جديده(رقم)` تكون لديها كل العناصر `غير معرفه`. للتهرب من هذه المفاجآت ، نستخدم عادةً الأقواس المربعة ، إلا إذا كنا نعرف حقًا ما نقوم به. +======= +To avoid such surprises, we usually use square brackets, unless we really know what we're doing. +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c ## مصفوفات متعدده الأبعاد diff --git a/1-js/05-data-types/08-weakmap-weakset/01-recipients-read/solution.md b/1-js/05-data-types/08-weakmap-weakset/01-recipients-read/solution.md index 6a4c20baf..e2147ccfa 100644 --- a/1-js/05-data-types/08-weakmap-weakset/01-recipients-read/solution.md +++ b/1-js/05-data-types/08-weakmap-weakset/01-recipients-read/solution.md @@ -25,7 +25,7 @@ messages.shift(); // now readMessages has 1 element (technically memory may be cleaned later) ``` -The `WeakSet` allows to store a set of messages and easily check for the existance of a message in it. +The `WeakSet` allows to store a set of messages and easily check for the existence of a message in it. It cleans up itself automatically. The tradeoff is that we can't iterate over it, can't get "all read messages" from it directly. But we can do it by iterating over all messages and filtering those that are in the set. diff --git a/1-js/05-data-types/08-weakmap-weakset/article.md b/1-js/05-data-types/08-weakmap-weakset/article.md index b9336405e..b89c9d17b 100644 --- a/1-js/05-data-types/08-weakmap-weakset/article.md +++ b/1-js/05-data-types/08-weakmap-weakset/article.md @@ -1,7 +1,11 @@  # النوع WeakMap والنوع WeakSet: الخرائط والأطقم ضعيفة الإشارة +<<<<<<< HEAD كما عرفنا من فصل «كنس المهملات»، فمُحرّك جافا سكريبت يخُزّن القيمة في الذاكرة طالما يمكن أن يصل لها شيء (أي يمكن استعمالها لاحقًا). هكذا: +======= +As we know from the chapter , JavaScript engine keeps a value in memory while it is "reachable" and can potentially be used. +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c ``` let john = { name: "John" }; 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 ed4ad83e5..53195032a 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 @@ -87,4 +87,8 @@ let doublePrices = Object.fromEntries( 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 diff --git a/1-js/05-data-types/11-date/article.md b/1-js/05-data-types/11-date/article.md index 8d5bcd01b..fc1b92800 100644 --- a/1-js/05-data-types/11-date/article.md +++ b/1-js/05-data-types/11-date/article.md @@ -318,7 +318,12 @@ function bench(f) { let time1 = 0; let time2 = 0; +<<<<<<< HEAD // ‫نشغّل bench(upperSlice)‎ وbench(upperLoop)‎ عشر مرات مرّة بمرّة +======= +*!* +// run bench(diffSubtract) and bench(diffGetTime) each 10 times alternating +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c for (let i = 0; i < 10; i++) { time1 += bench(diffSubtract); time2 += bench(diffGetTime); diff --git a/1-js/06-advanced-functions/03-closure/10-make-army/solution.md b/1-js/06-advanced-functions/03-closure/10-make-army/solution.md index b718b3668..99bb78edf 100644 --- a/1-js/06-advanced-functions/03-closure/10-make-army/solution.md +++ b/1-js/06-advanced-functions/03-closure/10-make-army/solution.md @@ -44,6 +44,7 @@ Let's examine what exactly happens inside `makeArmy`, and the solution will beco ``` 3. The array is returned from the function. +<<<<<<< HEAD Then, later, the call to any member, e.g. `army[5]()` will get the element `army[5]` from the array (which is a function) and calls it. @@ -138,6 +139,102 @@ Let's examine what exactly happens inside `makeArmy`, and the solution will beco That's essentially the same, because `for` on each iteration generates a new lexical environment, with its own variable `i`. So `shooter` generated in every iteration references its own `i`, from that very iteration. ![](lexenv-makearmy-for-fixed.svg) +======= + + Then, later, the call to any member, e.g. `army[5]()` will get the element `army[5]` from the array (which is a function) and calls it. + + Now why do all such functions show the same value, `10`? + + That's because there's no local variable `i` inside `shooter` functions. When such a function is called, it takes `i` from its outer lexical environment. + + Then, what will be the value of `i`? + + If we look at the source: + + ```js + function makeArmy() { + ... + let i = 0; + while (i < 10) { + let shooter = function() { // shooter function + alert( i ); // should show its number + }; + shooters.push(shooter); // add function to the array + i++; + } + ... + } + ``` + + We can see that all `shooter` functions are created in the lexical environment of `makeArmy()` function. But when `army[5]()` is called, `makeArmy` has already finished its job, and the final value of `i` is `10` (`while` stops at `i=10`). + + As the result, all `shooter` functions get the same value from the outer lexical environment and that is, the last value, `i=10`. + + ![](lexenv-makearmy-empty.svg) + + As you can see above, on each iteration of a `while {...}` block, a new lexical environment is created. So, to fix this, we can copy the value of `i` into a variable within the `while {...}` block, like this: + + ```js run + function makeArmy() { + let shooters = []; + + let i = 0; + while (i < 10) { + *!* + let j = i; + */!* + let shooter = function() { // shooter function + alert( *!*j*/!* ); // should show its number + }; + shooters.push(shooter); + i++; + } + + return shooters; + } + + let army = makeArmy(); + + // Now the code works correctly + army[0](); // 0 + army[5](); // 5 + ``` + + Here `let j = i` declares an "iteration-local" variable `j` and copies `i` into it. Primitives are copied "by value", so we actually get an independent copy of `i`, belonging to the current loop iteration. + + The shooters work correctly, because the value of `i` now lives a little bit closer. Not in `makeArmy()` Lexical Environment, but in the Lexical Environment that corresponds to the current loop iteration: + + ![](lexenv-makearmy-while-fixed.svg) + + Such a problem could also be avoided if we used `for` in the beginning, like this: + + ```js run demo + function makeArmy() { + + let shooters = []; + + *!* + for(let i = 0; i < 10; i++) { + */!* + let shooter = function() { // shooter function + alert( i ); // should show its number + }; + shooters.push(shooter); + } + + return shooters; + } + + let army = makeArmy(); + + army[0](); // 0 + army[5](); // 5 + ``` + + That's essentially the same, because `for` on each iteration generates a new lexical environment, with its own variable `i`. So `shooter` generated in every iteration references its own `i`, from that very iteration. + + ![](lexenv-makearmy-for-fixed.svg) +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c Now, as you've put so much effort into reading this, and the final recipe is so simple - just use `for`, you may wonder -- was it worth that? diff --git a/1-js/06-advanced-functions/03-closure/7-let-scope/solution.md b/1-js/06-advanced-functions/03-closure/7-let-scope/solution.md index 975c14d2e..f87f9ca53 100644 --- a/1-js/06-advanced-functions/03-closure/7-let-scope/solution.md +++ b/1-js/06-advanced-functions/03-closure/7-let-scope/solution.md @@ -24,8 +24,14 @@ In this example we can observe the peculiar difference between a "non-existing" ```js function func() { *!* +<<<<<<< HEAD // المتغير المحلي X يعتبر معروف للمحرك من البداية, لكن **غير معرف بقيمة** تظل حتي let // لذلك هناك خطأ +======= + // the local variable x is known to the engine from the beginning of the function, + // but "uninitialized" (unusable) until let ("dead zone") + // hence the error +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c */!* console.log(x); // ReferenceError: لا نستطيع الوصول لـ 'x' قبل إعطائها قيمة diff --git a/1-js/06-advanced-functions/03-closure/article.md b/1-js/06-advanced-functions/03-closure/article.md index 55cbb0902..27396d080 100644 --- a/1-js/06-advanced-functions/03-closure/article.md +++ b/1-js/06-advanced-functions/03-closure/article.md @@ -158,7 +158,11 @@ alert(counter()); // 2 فهم هذه الأشياء يعد عظيماً للمعلومات الشاملة لجافا سكريبت ومفيد جداً في حالة السيناريوهات المعقدة. لذلك هيا نتعمق أكثر في أمور أكثر صعوبة وتحتاج إلي تركيز. +<<<<<<< HEAD ## البيئات المعجمية +======= +Understanding such things is great for the overall knowledge of JavaScript and beneficial for more complex scenarios. So let's go a bit in-depth. +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c ```warn header="هنا يجب أن تكون شديد التركيز!" diff --git a/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/solution.md b/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/solution.md index e66eecae8..949e6bdda 100644 --- a/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/solution.md +++ b/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/solution.md @@ -56,6 +56,10 @@ function f(b) { } ``` +<<<<<<< HEAD وستُستعمل `‎f‎` هذه في الاستدعاء التالي، وتُعيد نفسها ثانيةً مهما لزم. وبعدها حين نستعمل العدد أو السلسلة النصية، يُعيد التابِع `‎toString‎` المجموع `‎currentSum‎`. يمكن أيضًا أن نستعمل `‎Symbol.toPrimitive‎` أو `‎valueOf‎` لإجراء عملية التحويل. ترجمة -وبتصرف- للفصل [Function object, NFE](https://javascript.info/function-object) من كتاب [The JavaScript language](https://javascript.info/js) +======= +This `f` will be used in the next call, again return itself, as many times as needed. Then, when used as a number or a string -- the `toString` returns the `currentSum`. We could also use `Symbol.toPrimitive` or `valueOf` here for the conversion. +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/solution.md b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/solution.md index cf851f771..6950664be 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/solution.md +++ b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/solution.md @@ -12,11 +12,10 @@ function throttle(func, ms) { savedThis = this; return; } + isThrottled = true; func.apply(this, arguments); // (1) - isThrottled = true; - setTimeout(function() { isThrottled = false; // (3) if (savedArgs) { diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/article.md b/1-js/06-advanced-functions/09-call-apply-decorators/article.md index 6bd5650fc..78300df66 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/article.md +++ b/1-js/06-advanced-functions/09-call-apply-decorators/article.md @@ -288,19 +288,34 @@ func.apply(context, args) أي أنّ الاستدعاءين الآتين متساويين تقريبًا: +<<<<<<< HEAD ``` func.call(context, ...args); // نمرّر الكائن قائمةً بمُعامل التوزيع func.apply(context, args); // ‫نفس الفكرة باستعمال apply ``` ولكن هناك فرق بسيط واحد: +======= +```js +func.call(context, ...args); +func.apply(context, args); +``` + +They perform the same call of `func` with given context and arguments. + +There's only a subtle difference regarding `args`: +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c - يُتيح لنا مُعامل التوزيع `‎...‎` تمرير _المُتعدَّد_ `‎args‎` قائمةً إلى `‎call‎`. - لا يقبل `‎apply‎` إلّا مُعامل `‎args‎` _شبيه بالمصفوفات_. +<<<<<<< HEAD أي أنّ هذين الاستدعاءين يُكمّلان بعضهما البعض. لو توقّعنا وصول مُتعدَّد فنستعمل `‎call‎`، ولو توقّعنا شبيهًا بالمصفوفات نستعمل `‎apply‎`. أمّا الكائنات المُتعدَّدة والشبيهة بالمصفوفات (مثل المصفوفات الحقيقية)، فيمكننا نظريًا استعمال أيّ من الاثنين، إلّا أنّ `‎apply‎` سيكون أسرع غالبًا إذ أنّ مُعظم محرّكات جافا سكريبت تحسّن أدائه داخليًا أكثر من `‎call‎`. +======= +...And for objects that are both iterable and array-like, such as a real array, we can use any of them, but `apply` will probably be faster, because most JavaScript engines internally optimize it better. +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c يُدى تمرير كافة المُعاملات (مع السياق) من دالة إلى أخرى _بتمرير الاستدعاء_. diff --git a/1-js/08-prototypes/01-prototype-inheritance/article.md b/1-js/08-prototypes/01-prototype-inheritance/article.md index 0db392e7f..761c3efde 100644 --- a/1-js/08-prototypes/01-prototype-inheritance/article.md +++ b/1-js/08-prototypes/01-prototype-inheritance/article.md @@ -10,7 +10,7 @@ _الوراثة النموذجية_ (تدعى أيضًا الوراثة عبر لكائنات جافا سكريبت خاصية مخفية أخرى باسم `[[Prototype]]` (هذا اسمها في المواصفات القياسية للغة جافا سكريبت)، وهي إمّا أن تكون `null` أو أن تشير إلى كائن آخر. نسمّي هذا الكائن بِـ”prototype“ (نموذج أولي). -When we read a property from `object`, and it's missing, JavaScript automatically takes it from the prototype. In programming, such thing is called "prototypal inheritance". And soon we'll study many examples of such inheritance, as well as cooler language features built upon it. +When we read a property from `object`, and it's missing, JavaScript automatically takes it from the prototype. In programming, this is called "prototypal inheritance". And soon we'll study many examples of such inheritance, as well as cooler language features built upon it. إن كائن النموذج الأولي ”سحريٌ“ إن صحّ القول، فحين نريد قراءة خاصية من كائن `object` ولا يجدها محرّك جافا سكريبت، يأخذها تلقائيًا من كائن النموذج الأولي لذاك الكائن. يُسمّى هذا في علم البرمجة ”بالوراثة النموذجية“ (‏Prototypal inheritance)، وهناك العديد من المزايا الرائعة في اللغة وفي التقنيات البرمجية مبنية عليها. diff --git a/1-js/08-prototypes/02-function-prototype/4-new-object-same-constructor/solution.md b/1-js/08-prototypes/02-function-prototype/4-new-object-same-constructor/solution.md index 0073e252e..372d50dd6 100644 --- a/1-js/08-prototypes/02-function-prototype/4-new-object-same-constructor/solution.md +++ b/1-js/08-prototypes/02-function-prototype/4-new-object-same-constructor/solution.md @@ -38,7 +38,12 @@ Why `user2.name` is `undefined`? Here's how `new user.constructor('Pete')` works: 1. First, it looks for `constructor` in `user`. Nothing. -2. Then it follows the prototype chain. The prototype of `user` is `User.prototype`, and it also has nothing. -3. The value of `User.prototype` is a plain object `{}`, its prototype is `Object.prototype`. And there is `Object.prototype.constructor == Object`. So it is used. +2. Then it follows the prototype chain. The prototype of `user` is `User.prototype`, and it also has no `constructor` (because we "forgot" to set it right!). +3. Going further up the chain, `User.prototype` is a plain object, its prototype is the built-in `Object.prototype`. +4. Finally, for the built-in `Object.prototype`, there's a built-in `Object.prototype.constructor == Object`. So it is used. -At the end, we have `let user2 = new Object('Pete')`. The built-in `Object` constructor ignores arguments, it always creates an empty object, similar to `let user2 = {}`, that's what we have in `user2` after all. +Finally, at the end, we have `let user2 = new Object('Pete')`. + +Probably, that's not what we want. We'd like to create `new User`, not `new Object`. That's the outcome of the missing `constructor`. + +(Just in case you're curious, the `new Object(...)` call converts its argument to an object. That's a theoretical thing, in practice no one calls `new Object` with a value, and generally we don't use `new Object` to make objects at all). \ No newline at end of file diff --git a/1-js/09-classes/01-class/article.md b/1-js/09-classes/01-class/article.md index 19711656e..13d908a22 100644 --- a/1-js/09-classes/01-class/article.md +++ b/1-js/09-classes/01-class/article.md @@ -112,7 +112,7 @@ alert(typeof User); // function alert(User === User.prototype.constructor); // true // The methods are in User.prototype, e.g: -alert(User.prototype.sayHi); // alert(this.name); +alert(User.prototype.sayHi); // the code of the sayHi method // there are exactly two methods in the prototype alert(Object.getOwnPropertyNames(User.prototype)); // constructor, sayHi @@ -146,7 +146,11 @@ user.sayHi(); لا تزال هناك اختلافات مهمة. +<<<<<<< HEAD 1. أولاً ، يتم تصنيف دالة تم إنشاؤها بواسطة "class" بواسطة خاصية داخلية خاصة `[[FunctionKind]]:" classConstructor "`. لذلك فهي ليست تمامًا مثل إنشائها يدويًا. +======= +1. First, a function created by `class` is labelled by a special internal property `[[IsClassConstructor]]: true`. So it's not entirely the same as creating it manually. +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c تقوم اللغة بالتحقق من هذه الخاصية في أماكن متنوعة. على سبيل المثال ، على عكس الوظيفة العادية ، يجب أن يتم استدعاؤها بـ `new`: 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 223926857..6df6ac7d5 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 @@ -188,7 +188,11 @@ new CoffeeMachine().setWaterAmount(100); يجب أن يبدأ الأفراد بـ `#`. يمكن الوصول إليها فقط من داخل الفصل. +<<<<<<< HEAD على سبيل المثال ، إليك خاصية `# waterLimit` الخاصة والطريقة الخاصة لفحص المياه` # checkWater`: +======= +For instance, here's a private `#waterLimit` property and the water-checking private method `#fixWaterAmount`: +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c ```js run class CoffeeMachine { diff --git a/1-js/11-async/02-promise-basics/article.md b/1-js/11-async/02-promise-basics/article.md index db389af88..a2b7cd7c8 100644 --- a/1-js/11-async/02-promise-basics/article.md +++ b/1-js/11-async/02-promise-basics/article.md @@ -22,6 +22,7 @@ let promise = new Promise(function (resolve, reject) { }); ``` +<<<<<<< HEAD تُدعى الدالة الممرّرة إلى `new Promise` ”بالمُنفِّذ“. متى صُنع الوعد `new Promise` عملت الدالة تلقائيًا. يحتوي هذا المُنفِّذ الشيفرة المُنتجِة، ويمكن أن تقدّم لنا في النهاية ناتجًا. في مثالنا أعلاه، فالمُنفِّذ هذا هو ”المغنّي“. تقدّم جافا سكريبت الوسيطين `resolve` و `reject` وهما ردود نداء. كما ولا نضع الشيفرة التي نريد تنفيذها إلا داخل المُنفِّذ. @@ -40,6 +41,25 @@ let promise = new Promise(function (resolve, reject) { [promise-resolve-reject.png] سنرى لاحقًا كيف سيشترك ”مُعجبونا“ بهذه التغييرات. إليك مثالًا عن بانيًا للوعود ودالة مُنفِّذ بسيطة فيها ”شيفرة مُنتجِة“ تأخذ بعض الوقت (باستعمال `setTimeout`): +======= +The function passed to `new Promise` is called the *executor*. When `new Promise` is created, the executor runs automatically. It contains the producing code which should eventually produce the result. In terms of the analogy above: the executor is the "singer". + +Its arguments `resolve` and `reject` are callbacks provided by JavaScript itself. Our code is only inside the executor. + +When the executor obtains the result, be it soon or late, doesn't matter, it should call one of these callbacks: + +- `resolve(value)` — if the job is finished successfully, with result `value`. +- `reject(error)` — if an error has occurred, `error` is the error object. + +So to summarize: the executor runs automatically and attempts to perform a job. When it is finished with the attempt, it calls `resolve` if it was successful or `reject` if there was an error. + +The `promise` object returned by the `new Promise` constructor has these internal properties: + +- `state` — initially `"pending"`, then changes to either `"fulfilled"` when `resolve` is called or `"rejected"` when `reject` is called. +- `result` — initially `undefined`, then changes to `value` when `resolve(value)` called or `error` when `reject(error)` is called. + +So the executor eventually moves `promise` to one of these states: +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c ``` let promise = new Promise(function(resolve, reject) { diff --git a/1-js/11-async/07-microtask-queue/article.md b/1-js/11-async/07-microtask-queue/article.md index e3a984add..c5a204b53 100644 --- a/1-js/11-async/07-microtask-queue/article.md +++ b/1-js/11-async/07-microtask-queue/article.md @@ -26,8 +26,12 @@ Asynchronous tasks need proper management. For that, the ECMA standard specifies كما هو مذكور في [المواصفات] (https://tc39.github.io/ecma262/#sec-jobs-and-job-queues): +<<<<<<< HEAD - قائمة الانتظار هي أول ما يخرج أولاً: يتم تنفيذ المهام المحددة أولاً. - يبدأ تنفيذ المهمة فقط في حالة عدم تشغيل أي شيء آخر. +======= +Or, to put it more simply, when a promise is ready, its `.then/catch/finally` handlers are put into the queue; they are not executed yet. When the JavaScript engine becomes free from the current code, it takes a task from the queue and executes it. +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c أو ، ببساطة ، عندما يكون الوعد جاهزًا ، يتم وضع معالجات "then / catch / وأخيرا" في قائمة الانتظار ؛ لم يتم إعدامهم بعد. عندما يصبح محرك JavaScript خاليًا من التعليمات البرمجية الحالية ، فإنه يأخذ مهمة من قائمة الانتظار وينفذها. @@ -38,7 +42,11 @@ Asynchronous tasks need proper management. For that, the ECMA standard specifies إذا كانت هناك سلسلة تحتوي على عدة ".then / catch / أخيرا" ، فسيتم تنفيذ كل واحد منها بشكل غير متزامن. أي أنه يتم وضعه في قائمة الانتظار أولاً ، ثم يتم تنفيذه عند اكتمال الرمز الحالي والانتهاء من معالجات قائمة الانتظار السابقة. +<<<<<<< HEAD ** ماذا لو كان الأمر يهمنا؟ كيف يمكننا أن نجعل "الشفرة منتهية" تعمل بعد "الوعد"؟ ** +======= +**What if the order matters for us? How can we make `code finished` appear after `promise done`?** +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c سهل ، ما عليك سوى وضعها في قائمة الانتظار باستخدام ".then`: diff --git a/1-js/11-async/08-async-await/article.md b/1-js/11-async/08-async-await/article.md index 8024e4cc5..f990a8f1d 100644 --- a/1-js/11-async/08-async-await/article.md +++ b/1-js/11-async/08-async-await/article.md @@ -70,9 +70,16 @@ f(); دعونا نؤكد: `` انتظارًا '' يجعل جافا سكريبت تنتظر حتى يستقر الوعد ، ثم استمر في النتيجة. هذا لا يكلف أي موارد وحدة المعالجة المركزية ، لأن المحرك يمكنه القيام بمهام أخرى في الوقت نفسه: تنفيذ البرامج النصية الأخرى ، والتعامل مع الأحداث ، وما إلى ذلك. +<<<<<<< HEAD Let's emphasize: `await` literally suspends the function execution until the promise settles, and then resumes it with the promise result. That doesn't cost any CPU resources, because the JavaScript engine can do other jobs in the meantime: execute other scripts, handle events, etc. ```` warn header="لا يمكن استخدام` انتظار 'في الوظائف العادية " إذا حاولنا استخدام `` انتظار '' في وظيفة غير متزامنة ، فسيكون هناك خطأ في بناء الجملة: +======= +It's just a more elegant syntax of getting the promise result than `promise.then`. And, it's easier to read and write. + +````warn header="Can't use `await` in regular functions" +If we try to use `await` in a non-async function, there would be a syntax error: +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c ```js run function f() { @@ -83,7 +90,12 @@ function f() { } ``` +<<<<<<< HEAD We may get this error if we forget to put `async` before a function. As said, `await` only works inside an `async` function. +======= +We may get this error if we forget to put `async` before a function. As stated earlier, `await` only works inside an `async` function. +```` +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c ````` @@ -190,7 +202,7 @@ class Waiter { new Waiter() .wait() - .then(alert); // 1 + .then(alert); // 1 (this is the same as (result => alert(result))) ``` The meaning is the same: it ensures that the returned value is a promise and enables `await`. diff --git a/1-js/12-generators-iterators/2-async-iterators-generators/article.md b/1-js/12-generators-iterators/2-async-iterators-generators/article.md index 2fed12e31..b79151ae4 100644 --- a/1-js/12-generators-iterators/2-async-iterators-generators/article.md +++ b/1-js/12-generators-iterators/2-async-iterators-generators/article.md @@ -389,6 +389,8 @@ More explanations about how it works: } } })(); + +// Note: If you are running this in an external sandbox, you'll need to paste here the function fetchCommits described above ``` That's just what we wanted. diff --git a/1-js/13-modules/01-modules-intro/article.md b/1-js/13-modules/01-modules-intro/article.md index 80570994a..0f37a9827 100644 --- a/1-js/13-modules/01-modules-intro/article.md +++ b/1-js/13-modules/01-modules-intro/article.md @@ -56,7 +56,7 @@ sayHi('John'); // Hello, John! يجلب المتصفّح الوحدة تلقائيًا ويقيم الشيفرة البرمجية بداخلها (ويستورد جميع الوحدات المتعلقة بها إن لزم الأمر)، وثمّ يشغلها. -```warn header="Modules work only via HTTP(s), not in local files" +```warn header="Modules work only via HTTP(s), not locally" If you try to open a web-page locally, via `file://` protocol, you'll find that `import/export` directives don't work. Use a local web-server, such as [static-server](https://www.npmjs.com/package/static-server#getting-started) or use the "live server" capability of your editor, such as VS Code [Live Server Extension](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer) to test modules. ``` @@ -70,7 +70,11 @@ If you try to open a web-page locally, via `file://` protocol, you'll find that ### الوضع الصارم الإفتراضي +<<<<<<< HEAD تستخدم الوحدات الوضع الصارم تلقائيًا فمثلًا إسناد قيمة لمتحول غير معرّف سينتج خطأ. +======= +Modules always work in strict mode. E.g. assigning to an undeclared variable will give an error. +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c ``` ``` +<<<<<<< HEAD ولو أردنا أن ننشئ متغير عام على مستوى النافذة يمكننا تعيينه صراحة للمتغيّر `window` ويمكننا الوصول إليه هكذا `window.user`. ولكن لابد من وجود سبب وجيهٍ لذلك. +======= +```smart +In the browser, we can make a variable window-level global by explicitly assigning it to a `window` property, e.g. `window.user = "John"`. + +Then all scripts will see it, both with `type="module"` and without it. + +That said, making such global variables is frowned upon. Please try to avoid them. +``` +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c ### تقييم شيفرة الوحدة لمرة واحدة فقط +<<<<<<< HEAD لو استوردتَ نفس الوحدة في أكثر من مكان، فلا تُنفّذ شيفرتها إلّا مرة واحدة، وبعدها تُصدّر إلى من استوردها. ولهذا توابع مهمّ معرفتها. لنرى بعض الأمثلة. +======= +If the same module is imported into multiple other modules, its code is executed only once, upon the first import. Then its exports are given to all further importers. + +The one-time evaluation has important consequences, that we should be aware of. + +Let's see a couple of examples. +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c أولًا، لو كان لشيفرة الوحدة التي ستُنفّذ أيّ تأثيرات (مثل عرض رسالة أو ما شابه)، فاستيرادها أكثر من مرّة سيشغّل ذلك التأثير مرة واحدة، وهي أول مرة فقط: @@ -134,9 +175,17 @@ import `./alert.js`; // ‫نُفّذت شيفرة الوحدة! import `./alert.js`; // (لا نرى شيئًا هنا) ``` +<<<<<<< HEAD في الواقع، فشيفرات الوحدات عالية المستوى في بنية البرمجية لا تُستعمل إلّا لتمهيد بنى البيانات الداخلية وإنشائها. ولو أردنا شيئًا نُعيد استعماله، نُصدّر الوحدة. الآن حان وقت مثال مستواه متقدّم أكثر. +======= +The second import shows nothing, because the module has already been evaluated. + +There's a rule: top-level module code should be used for initialization, creation of module-specific internal data structures. If we need to make something callable multiple times - we should export it as a function, like we did with `sayHi` above. + +Now, let's consider a deeper example. +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c لنقل بأنّ هناك وحدة تُصدّر كائنًا: @@ -161,6 +210,7 @@ import {admin} from './admin.js'; alert(admin.name); // Pete *!* +<<<<<<< HEAD // ‫كِلا الملفين ‎1.js و ‎2.js سيستوردان نفس الكائن // ‫التغييرات الّتي ستحدثُ في الملف ‎1.js ستكون مرئية في الملف ‎2.js */!* @@ -171,45 +221,90 @@ alert(admin.name); // Pete يتيح لنا هذا السلوك ”ضبط“ الوحدة عند أوّل استيراد لها، فنضبط خاصياتها المرة الأولى، ومتى ما استوُردت مرة أخرى تكون جاهزة. فمثلًا قد تقدّم لنا وحدة `admin.js` بعض المزايا ولكن تطلب أن تأتي امتيازات الإدارة من خارج كائن `admin` إلى داخله: +======= +// Both 1.js and 2.js reference the same admin object +// Changes made in 1.js are visible in 2.js +*/!* +``` + +As you can see, when `1.js` changes the `name` property in the imported `admin`, then `2.js` can see the new `admin.name`. + +That's exactly because the module is executed only once. Exports are generated, and then they are shared between importers, so if something changes the `admin` object, other modules will see that. + +**Such behavior is actually very convenient, because it allows us to *configure* modules.** + +In other words, a module can provide a generic functionality that needs a setup. E.g. authentication needs credentials. Then it can export a configuration object expecting the outer code to assign to it. + +Here's the classical pattern: +1. A module exports some means of configuration, e.g. a configuration object. +2. On the first import we initialize it, write to its properties. The top-level application script may do that. +3. Further imports use the module. + +For instance, the `admin.js` module may provide certain functionality (e.g. authentication), but expect the credentials to come into the `config` object from outside: +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c ``` // 📁 admin.js -export let admin = { }; +export let config = { }; export function sayHi() { - alert(`Ready to serve, ${admin.name}!`); + alert(`Ready to serve, ${config.user}!`); } ``` +<<<<<<< HEAD نضبط في `init.js` (أوّل نص برمجي لتطبيقنا) المتغير `admin.name`. بعدها سيراه كلّ من أراد بما في ذلك الاستدعاءات من داخل وحدة `admin.js` نفسها: +======= +Here, `admin.js` exports the `config` object (initially empty, but may have default properties too). + +Then in `init.js`, the first script of our app, we import `config` from it and set `config.user`: +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c ``` // 📁 init.js -import {admin} from './admin.js'; -admin.name = "Pete"; +import {config} from './admin.js'; +config.user = "Pete"; ``` +<<<<<<< HEAD ويمكن لوحدة أخرى استعمال `admin.name`: ``` // 📁 other.js import {admin, sayHi} from './admin.js'; +======= +...Now the module `admin.js` is configured. -alert(admin.name); // *!*Pete*/!* +Further importers can call it, and it correctly shows the current user: +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c + +```js +// 📁 another.js +import {sayHi} from './admin.js'; sayHi(); // Ready to serve, *!*Pete*/!*! ``` + ### import.meta يحتوي الكائن `import.meta` على معلومات الوحدة الحالية. +<<<<<<< HEAD ويعتمد محتواها على البيئة الحالية، ففي المتصفّحات يحتوي على عنوان النص البرمجي أو عنوان صفحة الوِب الحالية لو كان داخل HTML: +======= +Its content depends on the environment. In the browser, it contains the URL of the script, or a current webpage URL if inside HTML: +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c ``` html run height=0 ``` diff --git a/1-js/99-js-misc/04-reference-type/article.md b/1-js/99-js-misc/04-reference-type/article.md index c291abc05..87fca770f 100644 --- a/1-js/99-js-misc/04-reference-type/article.md +++ b/1-js/99-js-misc/04-reference-type/article.md @@ -3,7 +3,14 @@ ```warn header="خصائص متقدمه فى اللغه" هذه المقالة تقوم بتغطية موضوع متقدم, لفهم بعض الحالات بشكل أفضل. +<<<<<<< HEAD إنها ليست مهمة. يعيش العديد من المطورين ذوي الخبرة بشكل جيد دون معرفة ذلك. تابع القراءة إذا كنت تريد معرفة كيفية عمل الأشياء خلف الكواليس. +======= +```warn header="In-depth language feature" +This article covers an advanced topic, to understand certain edge-cases better. + +It's not important. Many experienced developers live fine without knowing it. Read on if you want to know how things work under the hood. +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c ``` قد تفقد استدعاء تابع تم تقييمه بشكل ديناميكي `this`. diff --git a/2-ui/1-document/03-dom-navigation/article.md b/2-ui/1-document/03-dom-navigation/article.md index f7123d70d..b5f03098c 100644 --- a/2-ui/1-document/03-dom-navigation/article.md +++ b/2-ui/1-document/03-dom-navigation/article.md @@ -214,7 +214,7 @@ alert( document.body.previousSibling ); // HTMLHeadElement ## Element-only navigation -Navigation properties listed above refer to *all* nodes. For instance, in `childNodes` we can see both text nodes, element nodes, and even comment nodes if there exist. +Navigation properties listed above refer to *all* nodes. For instance, in `childNodes` we can see both text nodes, element nodes, and even comment nodes if they exist. But for many tasks we don't want text or comment nodes. We want to manipulate element nodes that represent tags and form the structure of the page. diff --git a/2-ui/1-document/07-modifying-document/5-why-aaa/solution.md b/2-ui/1-document/07-modifying-document/5-why-aaa/solution.md index 6b85168b9..3d1f6698f 100644 --- a/2-ui/1-document/07-modifying-document/5-why-aaa/solution.md +++ b/2-ui/1-document/07-modifying-document/5-why-aaa/solution.md @@ -1,9 +1,9 @@ The HTML in the task is incorrect. That's the reason of the odd thing. -The browser has to fix it automatically. But there may be no text inside the ``: according to the spec only table-specific tags are allowed. So the browser adds `"aaa"` *before* the `
`. +The browser has to fix it automatically. But there may be no text inside the `
`: according to the spec only table-specific tags are allowed. So the browser shows `"aaa"` *before* the `
`. Now it's obvious that when we remove the table, it remains. -The question can be easily answered by exploring the DOM using the browser tools. It shows `"aaa"` before the `
`. +The question can be easily answered by exploring the DOM using the browser tools. You'll see `"aaa"` before the `
`. The HTML standard specifies in detail how to process bad HTML, and such behavior of the browser is correct. diff --git a/2-ui/1-document/10-size-and-scroll-window/article.md b/2-ui/1-document/10-size-and-scroll-window/article.md index d0985f3ad..5e240c415 100644 --- a/2-ui/1-document/10-size-and-scroll-window/article.md +++ b/2-ui/1-document/10-size-and-scroll-window/article.md @@ -77,7 +77,17 @@ alert('Current scroll from the left: ' + window.pageXOffset); هذه الخصائص للقراءة فقط. +<<<<<<< HEAD ## التمرير: التمرير إلى التمرير التمرير التمرير العرضي [# window-تمرير] +======= +```smart header="Also available as `window` properties `scrollX` and `scrollY`" +For historical reasons, both properties exist, but they are the same: +- `window.pageXOffset` is an alias of `window.scrollX`. +- `window.pageYOffset` is an alias of `window.scrollY`. +``` + +## Scrolling: scrollTo, scrollBy, scrollIntoView [#window-scroll] +>>>>>>> fb4fc33a2234445808100ddc9f5e4dcec8b3d24c ```warn To scroll the page with JavaScript, its DOM must be fully built. diff --git a/2-ui/3-event-details/4-mouse-drag-and-drop/article.md b/2-ui/3-event-details/4-mouse-drag-and-drop/article.md index 6cb1152c1..49ab88be2 100644 --- a/2-ui/3-event-details/4-mouse-drag-and-drop/article.md +++ b/2-ui/3-event-details/4-mouse-drag-and-drop/article.md @@ -124,7 +124,7 @@ Let's update our algorithm: ```js // onmousemove - // ball has position:absoute + // ball has position:absolute ball.style.left = event.pageX - *!*shiftX*/!* + 'px'; ball.style.top = event.pageY - *!*shiftY*/!* + 'px'; ``` diff --git a/2-ui/4-forms-controls/2-focus-blur/4-edit-td-click/task.md b/2-ui/4-forms-controls/2-focus-blur/4-edit-td-click/task.md index 2cccea020..378bd1f54 100644 --- a/2-ui/4-forms-controls/2-focus-blur/4-edit-td-click/task.md +++ b/2-ui/4-forms-controls/2-focus-blur/4-edit-td-click/task.md @@ -6,7 +6,7 @@ importance: 5 Make table cells editable on click. -- On click -- the cell should became "editable" (textarea appears inside), we can change HTML. There should be no resize, all geometry should remain the same. +- On click -- the cell should become "editable" (textarea appears inside), we can change HTML. There should be no resize, all geometry should remain the same. - Buttons OK and CANCEL appear below the cell to finish/cancel the editing. - Only one cell may be editable at a moment. While a `
` is in "edit mode", clicks on other cells are ignored. - The table may have many cells. Use event delegation. diff --git a/2-ui/4-forms-controls/2-focus-blur/5-keyboard-mouse/task.md b/2-ui/4-forms-controls/2-focus-blur/5-keyboard-mouse/task.md index fc48c21ff..644d814d9 100644 --- a/2-ui/4-forms-controls/2-focus-blur/5-keyboard-mouse/task.md +++ b/2-ui/4-forms-controls/2-focus-blur/5-keyboard-mouse/task.md @@ -9,4 +9,5 @@ Focus on the mouse. Then use arrow keys to move it: [demo src="solution"] P.S. Don't put event handlers anywhere except the `#mouse` element. + P.P.S. Don't modify HTML/CSS, the approach should be generic and work with any element. diff --git a/2-ui/4-forms-controls/2-focus-blur/article.md b/2-ui/4-forms-controls/2-focus-blur/article.md index d4348d25b..b866a5e2b 100644 --- a/2-ui/4-forms-controls/2-focus-blur/article.md +++ b/2-ui/4-forms-controls/2-focus-blur/article.md @@ -104,7 +104,7 @@ The best recipe is to be careful when using these events. If we want to track us ``` ## Allow focusing on any element: tabindex -By default many elements do not support focusing. +By default, many elements do not support focusing. The list varies a bit between browsers, but one thing is always correct: `focus/blur` support is guaranteed for elements that a visitor can interact with: ` + ## Selection properties -Similar to a range, a selection has a start, called "anchor", and the end, called "focus". +As said, a selection may in theory contain multiple ranges. We can get these range objects using the method: + +- `getRangeAt(i)` -- get i-th range, starting from `0`. In all browsers except Firefox, only `0` is used. + +Also, there exist properties that often provide better convenience. + +Similar to a range, a selection object has a start, called "anchor", and the end, called "focus". The main selection properties are: @@ -294,36 +352,39 @@ The main selection properties are: - `isCollapsed` -- `true` if selection selects nothing (empty range), or doesn't exist. - `rangeCount` -- count of ranges in the selection, maximum `1` in all browsers except Firefox. -````smart header="Usually, the selection end `focusNode` is after its start `anchorNode`, but it's not always the case" -There are many ways to select the content, depending on the user agent: mouse, hotkeys, taps on a mobile etc. +```smart header="Selection end/start vs Range" + +There's an important differences of a selection anchor/focus compared with a `Range` start/end. + +As we know, `Range` objects always have their start before the end. -Some of them, such as a mouse, allow the same selection can be created in two directions: "left-to-right" and "right-to-left". +For selections, that's not always the case. -If the start (anchor) of the selection goes in the document before the end (focus), this selection is said to have "forward" direction. +Selecting something with a mouse can be done in both directions: either "left-to-right" or "right-to-left". + +In other words, when the mouse button is pressed, and then it moves forward in the document, then its end (focus) will be after its start (anchor). E.g. if the user starts selecting with mouse and goes from "Example" to "italic": ![](selection-direction-forward.svg) -Otherwise, if they go from the end of "italic" to "Example", the selection is directed "backward", its focus will be before the anchor: +...But the same selection could be done backwards: starting from "italic" to "Example" (backward direction), then its end (focus) will be before the start (anchor): ![](selection-direction-backward.svg) - -That's different from `Range` objects that are always directed forward: the range start can't be after its end. -```` +``` ## Selection events There are events on to keep track of selection: -- `elem.onselectstart` -- when a selection starts on `elem`, e.g. the user starts moving mouse with pressed button. - - Preventing the default action makes the selection not start. -- `document.onselectionchange` -- whenever a selection changes. - - Please note: this handler can be set only on `document`. +- `elem.onselectstart` -- when a selection *starts* specifically on element `elem` (or inside it). For instance, when the user presses the mouse button on it and starts to move the pointer. + - Preventing the default action cancels the selection start. So starting a selection from this element becomes impossible, but the element is still selectable. The visitor just needs to start the selection from elsewhere. +- `document.onselectionchange` -- whenever a selection changes or starts. + - Please note: this handler can be set only on `document`, it tracks all selections in it. ### Selection tracking demo -Here's a small demo that shows selection boundaries dynamically as it changes: +Here's a small demo. It tracks the current selection on the `document` and shows its boundaries: ```html run height=80

Select me: italic and bold

@@ -331,21 +392,25 @@ Here's a small demo that shows selection boundaries dynamically as it changes: From – To ``` -### Selection getting demo +### Selection copying demo + +There are two approaches to copying the selected content: -To get the whole selection: -- As text: just call `document.getSelection().toString()`. -- As DOM nodes: get the underlying ranges and call their `cloneContents()` method (only first range if we don't support Firefox multiselection). +1. We can use `document.getSelection().toString()` to get it as text. +2. Otherwise, to copy the full DOM, e.g. if we need to keep formatting, we can get the underlying ranges with `getRangesAt(...)`. A `Range` object, in turn, has `cloneContents()` method that clones its content and returns as `DocumentFragment` object, that we can insert elsewhere. -And here's the demo of getting the selection both as text and as DOM nodes: +Here's the demo of copying the selected content both as text and as DOM nodes: ```html run height=100

Select me: italic and bold

@@ -373,15 +438,15 @@ As text: ## Selection methods -Selection methods to add/remove ranges: +We can work with the selection by addding/removing ranges: -- `getRangeAt(i)` -- get i-th range, starting from `0`. In all browsers except firefox, only `0` is used. +- `getRangeAt(i)` -- get i-th range, starting from `0`. In all browsers except Firefox, only `0` is used. - `addRange(range)` -- add `range` to selection. All browsers except Firefox ignore the call, if the selection already has an associated range. - `removeRange(range)` -- remove `range` from the selection. - `removeAllRanges()` -- remove all ranges. - `empty()` -- alias to `removeAllRanges`. -Also, there are convenience methods to manipulate the selection range directly, without `Range`: +There are also convenience methods to manipulate the selection range directly, without intermediate `Range` calls: - `collapse(node, offset)` -- replace selected range with a new one that starts and ends at the given `node`, at position `offset`. - `setPosition(node, offset)` -- alias to `collapse`. @@ -393,7 +458,7 @@ Also, there are convenience methods to manipulate the selection range directly, - `deleteFromDocument()` -- remove selected content from the document. - `containsNode(node, allowPartialContainment = false)` -- checks whether the selection contains `node` (partially if the second argument is `true`) -So, for many tasks we can call `Selection` methods, no need to access the underlying `Range` object. +For most tasks these methods are just fine, there's no need to access the underlying `Range` object. For example, selecting the whole contents of the paragraph `

`: @@ -420,10 +485,10 @@ The same thing using ranges: ``` -```smart header="To select, remove the existing selection first" -If the selection already exists, empty it first with `removeAllRanges()`. And then add ranges. Otherwise, all browsers except Firefox ignore new ranges. +```smart header="To select something, remove the existing selection first" +If a document selection already exists, empty it first with `removeAllRanges()`. And then add ranges. Otherwise, all browsers except Firefox ignore new ranges. -The exception is some selection methods, that replace the existing selection, like `setBaseAndExtent`. +The exception is some selection methods, that replace the existing selection, such as `setBaseAndExtent`. ``` ## Selection in form controls diff --git a/2-ui/99-ui-misc/02-selection-range/range-hello-1.svg b/2-ui/99-ui-misc/02-selection-range/range-hello-1.svg new file mode 100644 index 000000000..90054cef1 --- /dev/null +++ b/2-ui/99-ui-misc/02-selection-range/range-hello-1.svg @@ -0,0 +1 @@ +<p>Hello</p>p.firstChild \ No newline at end of file diff --git a/4-binary/03-blob/article.md b/4-binary/03-blob/article.md index a44308f6f..5031afa32 100644 --- a/4-binary/03-blob/article.md +++ b/4-binary/03-blob/article.md @@ -74,7 +74,7 @@ link.href = URL.createObjectURL(blob); We can also create a link dynamically in JavaScript and simulate a click by `link.click()`, then download starts automatically. -Here's the similar code that causes user to download the dynamicallly created `Blob`, without any HTML: +Here's the similar code that causes user to download the dynamically created `Blob`, without any HTML: ```js run let link = document.createElement('a'); @@ -186,7 +186,7 @@ let context = canvas.getContext('2d'); context.drawImage(img, 0, 0); // we can context.rotate(), and do many other things on canvas -// toBlob is async opereation, callback is called when done +// toBlob is async operation, callback is called when done canvas.toBlob(function(blob) { // blob ready, download it let link = document.createElement('a'); @@ -235,7 +235,7 @@ That makes Blobs convenient for upload/download operations, that are so common i Methods that perform web-requests, such as [XMLHttpRequest](info:xmlhttprequest), [fetch](info:fetch) and so on, can work with `Blob` natively, as well as with other binary types. -We can easily convert betweeen `Blob` and low-level binary data types: +We can easily convert between `Blob` and low-level binary data types: - We can make a Blob from a typed array using `new Blob(...)` constructor. - We can get back `ArrayBuffer` from a Blob using `FileReader`, and then create a view over it for low-level binary processing. diff --git a/5-network/03-fetch-progress/article.md b/5-network/03-fetch-progress/article.md index f5a64da54..c0e3d922a 100644 --- a/5-network/03-fetch-progress/article.md +++ b/5-network/03-fetch-progress/article.md @@ -9,7 +9,7 @@ To track download progress, we can use `response.body` property. It's `ReadableS Unlike `response.text()`, `response.json()` and other methods, `response.body` gives full control over the reading process, and we can count how much is consumed at any moment. -Here's the sketch of code that reads the reponse from `response.body`: +Here's the sketch of code that reads the response from `response.body`: ```js // instead of response.json() and other methods diff --git a/5-network/06-fetch-api/article.md b/5-network/06-fetch-api/article.md index e57689c75..eea5030b6 100644 --- a/5-network/06-fetch-api/article.md +++ b/5-network/06-fetch-api/article.md @@ -171,7 +171,7 @@ The `redirect` option allows to change that: - **`"follow"`** -- the default, follow HTTP-redirects, - **`"error"`** -- error in case of HTTP-redirect, -- **`"manual"`** -- allows to process HTTP-redirects manually. In case of redirect, we'll get a special response object, with `response.type="opaqueredirect"` and and zeroed/empty status and most other properies. +- **`"manual"`** -- allows to process HTTP-redirects manually. In case of redirect, we'll get a special response object, with `response.type="opaqueredirect"` and zeroed/empty status and most other properies. ## integrity diff --git a/5-network/11-websocket/article.md b/5-network/11-websocket/article.md index aab6d31be..8193f8419 100644 --- a/5-network/11-websocket/article.md +++ b/5-network/11-websocket/article.md @@ -88,7 +88,7 @@ Sec-WebSocket-Key: Iv8io/9s+lYFgZWcXczP8Q== Sec-WebSocket-Version: 13 ``` -- `Origin` -- the origin of the client page, e.g. `https://javascript.info`. WebSocket objects are cross-origin by nature. There are no special headers or other limitations. Old servers are unable to handle WebSocket anyway, so there are no compabitility issues. But `Origin` header is important, as it allows the server to decide whether or not to talk WebSocket with this website. +- `Origin` -- the origin of the client page, e.g. `https://javascript.info`. WebSocket objects are cross-origin by nature. There are no special headers or other limitations. Old servers are unable to handle WebSocket anyway, so there are no compatibility issues. But `Origin` header is important, as it allows the server to decide whether or not to talk WebSocket with this website. - `Connection: Upgrade` -- signals that the client would like to change the protocol. - `Upgrade: websocket` -- the requested protocol is "websocket". - `Sec-WebSocket-Key` -- a random browser-generated key for security. diff --git a/6-data-storage/01-cookie/article.md b/6-data-storage/01-cookie/article.md index 9fc5f6955..ac2fda063 100644 --- a/6-data-storage/01-cookie/article.md +++ b/6-data-storage/01-cookie/article.md @@ -247,8 +247,11 @@ But anything more complicated, like a network request from another site or a for If that's fine for you, then adding `samesite=lax` will probably not break the user experience and add protection. -Overall, `samesite` is a great option, but it has an important drawback: -- `samesite` is ignored (not supported) by old browsers, year 2017 or so. +Overall, `samesite` is a great option. + +There's a drawback: + +- `samesite` is ignored (not supported) by very old browsers, year 2017 or so. **So if we solely rely on `samesite` to provide protection, then old browsers will be vulnerable.** diff --git a/6-data-storage/02-localstorage/article.md b/6-data-storage/02-localstorage/article.md index e2e2751db..d0483f3a3 100644 --- a/6-data-storage/02-localstorage/article.md +++ b/6-data-storage/02-localstorage/article.md @@ -127,17 +127,17 @@ Please note that both key and value must be strings. If were any other type, like a number, or an object, it gets converted to string automatically: ```js run -sessionStorage.user = {name: "John"}; -alert(sessionStorage.user); // [object Object] +localStorage.user = {name: "John"}; +alert(localStorage.user); // [object Object] ``` We can use `JSON` to store objects though: ```js run -sessionStorage.user = JSON.stringify({name: "John"}); +localStorage.user = JSON.stringify({name: "John"}); // sometime later -let user = JSON.parse( sessionStorage.user ); +let user = JSON.parse( localStorage.user ); alert( user.name ); // John ``` diff --git a/6-data-storage/03-indexeddb/article.md b/6-data-storage/03-indexeddb/article.md index a4fb78c1e..19b5d7e9c 100644 --- a/6-data-storage/03-indexeddb/article.md +++ b/6-data-storage/03-indexeddb/article.md @@ -5,7 +5,7 @@ libs: # IndexedDB -IndexedDB is a database that is built into browser, much more powerful than `localStorage`. +IndexedDB is a database that is built into a browser, much more powerful than `localStorage`. - Stores almost any kind of values by keys, multiple key types. - Supports transactions for reliability. @@ -50,7 +50,7 @@ Unlike server-side databases, IndexedDB is client-side, the data is stored in th If the local database version is less than specified in `open`, then a special event `upgradeneeded` is triggered, and we can compare versions and upgrade data structures as needed. -The `upgradeneeded` event also triggers when the database doesn't yet exist (technically, it's version is `0`), so we can perform the initialization. +The `upgradeneeded` event also triggers when the database doesn't yet exist (technically, its version is `0`), so we can perform the initialization. Let's say we published the first version of our app. @@ -95,7 +95,7 @@ openRequest.onupgradeneeded = function(event) { }; ``` -Please note: as our current version is `2`, `onupgradeneeded` handler has a code branch for version `0`, suitable for users that are accessing for the first time and have no database, and also for version `1`, for upgrades. +Please note: as our current version is `2`, the `onupgradeneeded` handler has a code branch for version `0`, suitable for users that are accessing for the first time and have no database, and also for version `1`, for upgrades. And then, only if `onupgradeneeded` handler finishes without errors, `openRequest.onsuccess` triggers, and the database is considered successfully opened. @@ -156,7 +156,7 @@ openRequest.onsuccess = function() { openRequest.onblocked = function() { // this event shouldn't trigger if we handle onversionchange correctly - // it means that there's another open connection to same database + // it means that there's another open connection to the same database // and it wasn't closed after db.onversionchange triggered for it }; */!* @@ -171,7 +171,7 @@ We can handle things more gracefully in `db.onversionchange`, prompt the visitor Or, an alternative approach would be to not close the database in `db.onversionchange`, but instead use the `onblocked` handler (in the new tab) to alert the visitor, tell him that the newer version can't be loaded until they close other tabs. -These update collisions happen rarely, but we should at least have some handling for them, at least `onblocked` handler, to prevent our script from dying silently. +These update collisions happen rarely, but we should at least have some handling for them, at least an `onblocked` handler, to prevent our script from dying silently. ## Object store @@ -189,7 +189,7 @@ An example of an object that can't be stored: an object with circular references **There must be a unique `key` for every value in the store.** -A key must be one of the these types - number, date, string, binary, or array. It's a unique identifier, so we can search/remove/update values by the key. +A key must be one of these types - number, date, string, binary, or array. It's a unique identifier, so we can search/remove/update values by the key. ![](indexeddb-structure.svg) @@ -253,7 +253,7 @@ db.deleteObjectStore('books') The term "transaction" is generic, used in many kinds of databases. -A transaction is a group operations, that should either all succeed or all fail. +A transaction is a group of operations, that should either all succeed or all fail. For instance, when a person buys something, we need to: 1. Subtract the money from their account. @@ -347,9 +347,9 @@ Usually, we can assume that a transaction commits when all its requests are comp So, in the example above no special call is needed to finish the transaction. -Transactions auto-commit principle has an important side effect. We can't insert an async operation like `fetch`, `setTimeout` in the middle of transaction. IndexedDB will not keep the transaction waiting till these are done. +Transactions auto-commit principle has an important side effect. We can't insert an async operation like `fetch`, `setTimeout` in the middle of a transaction. IndexedDB will not keep the transaction waiting till these are done. -In the code below, `request2` in line `(*)` fails, because the transaction is already committed, and can't make any request in it: +In the code below, `request2` in the line `(*)` fails, because the transaction is already committed, and can't make any request in it: ```js let request1 = books.add(book); @@ -370,7 +370,7 @@ That's because `fetch` is an asynchronous operation, a macrotask. Transactions a Authors of IndexedDB spec believe that transactions should be short-lived. Mostly for performance reasons. -Notably, `readwrite` transactions "lock" the stores for writing. So if one part of application initiated `readwrite` on `books` object store, then another part that wants to do the same has to wait: the new transaction "hangs" till the first one is done. That can lead to strange delays if transactions take a long time. +Notably, `readwrite` transactions "lock" the stores for writing. So if one part of the application initiated `readwrite` on `books` object store, then another part that wants to do the same has to wait: the new transaction "hangs" till the first one is done. That can lead to strange delays if transactions take a long time. So, what to do? @@ -792,7 +792,7 @@ await inventory.add({ id: 'js', price: 10, created: new Date() }); // Error The next `inventory.add` after `fetch` `(*)` fails with an "inactive transaction" error, because the transaction is already committed and closed at that time. -The workaround is same as when working with native IndexedDB: either make a new transaction or just split things apart. +The workaround is the same as when working with native IndexedDB: either make a new transaction or just split things apart. 1. Prepare the data and fetch all that's needed first. 2. Then save in the database. diff --git a/8-web-components/2-custom-elements/article.md b/8-web-components/2-custom-elements/article.md index 13af80b8c..a84ed1192 100644 --- a/8-web-components/2-custom-elements/article.md +++ b/8-web-components/2-custom-elements/article.md @@ -365,7 +365,7 @@ Our new button extends the built-in one. So it keeps the same styles and standar ## References - HTML Living Standard: . -- Compatiblity: . +- Compatiblity: . ## Summary @@ -397,4 +397,4 @@ Custom elements can be of two types: /*