The modern mode, "use strict" To keep old version of code working "use strict" in the top.
Variable is name of data storage. There is 2 type of variables, "let" and "const". let - variable that can be changet const - this variable cannot be changet.
A variable in JS can contain any data. There is a 7 different data types name: 1."number" - for number 2."boolean" - true/false 3."string" - for strings 4."symbol" - unique identifiers
when we type let someVariable = null, we clear value of this variable. So null is value with nothing.
There is also 2 form of typeof without any difference "typeof x and typeof(x)"
We can convert value type. Also JS have functions that automatically convert.
An operand – is what operators are applied to. For instance, in the multiplication of 5 * 2 there are two operands: the left operand is 5 and the right operand is 2. Sometimes, people call these “arguments” instead of “operands”.
An operator is unary if it has a single operand. For example, the unary negation - reverses the sign of a number. An operator is binary if it has two operands.
Remainder %
The result of a % b is the remainder of the integer division of a by b.
Exponentiation For a natural number b, the result of a b is a multiplied by itself b times.
Increment/decrement Increment ++ increases a variable by 1 a++ = a+1;
Decrement -- decreases a variable by 1 a-- = a-1;
!!! Increment/decrement can only be applied to variables. Trying to use it on a value like 5++ will give an error. !!!
Bitwise operators AND - ( & ) OR - ( | ) XOR - ( ^ ) NOT = ( ~ ) LEFT SHIFT - ( << ) RIGHT SHIFT - ( >> ) ZERO-FILL RIGHT SHIFT - ( >>> )
Comma (rare to use) The comma operator allows us to evaluate several expressions, dividing them with a comma ,. Each of them is evaluated but only the result of the last one is returned.
Comparison type: '<, >, =, >=, <=, !=, ===, ==,' When we use 'if', condition was already boolean. for example: if (something) { .. } 'something' - boolean.
true - yes(1) /correct false - no(0) / wrong We use comparing ofter for compare something to perform actions under a certain condition Comparison operators return a boolean value. Strings are compared letter-by-letter in the “dictionary” order.
all this scripts paused script execution
alert
alert(message);
promt
Sshow a message and paused script until you press "OK" It returns the text or, if CANCEL or Esc is clicked, null.
result = prompt(title[, default]);
promt accepts two arguments, first will show message(before coma) and second will shows an input field.
confirm
result = confirm(question);
show message with two option "OK" and "CANCLE", just for boolean.
The if statement evaluates a condition and, if the condition’s result is true, executes a block of code.
The if (…) statement evaluates the expression in its parentheses and converts the result to a boolean.
The if statement may contain an optional “else” block. It executes when the condition is false.
We can do multiplicate time "else if" if its needed. Same as "else"
same as "if, else" but with ternary operator its much simple and shorter. Example:
let result = condition ? value1 : value2;
Example:
let age = prompt('age?', 18);
let message = (age < 3) ? 'Hi, baby!' :
(age < 18) ? 'Hello!' :
(age < 100) ? 'Greetings!' :
'What an unusual age!';
alert( message );
with ternary operator "?" :
let age = prompt('age?', 18);
let message = (age < 3) ? 'Hi, baby!' :
(age < 18) ? 'Hello!' :
(age < 100) ? 'Greetings!' :
'What an unusual age!';
alert( message );
There are three logical operators in JavaScript:
Getting the first truthy value from a list of variables or expressions.
&& (AND) finds the first falsy value The AND && operator does the following: Evaluates operands from left to right. For each operand, converts it to a boolean. If the result isfalse, stops and returns the original value of that operand. If all operands have been evaluated (i.e. all were truthy),returns the last operand.
So the code a && b || c && d is essentially the same as if the && expressions were in parentheses: (a && b) || (c && d).
Just like OR, the AND && operator can sometimes replace if.
let x = 1;
(x > 0) && alert( 'Greater than zero!' );
The action in the right part of && would execute only if the evaluation reaches it. That is, only if (x > 0) is true.
transform to standart:
let x = 1;
if (x > 0) {
alert( 'Greater than zero!' );
}
result = !value;
The operator accepts a single argument and does the following:
Converts the operand to boolean type: true/false.
Returns the inverse value.
A double NOT !! is sometimes used for converting a value to boolean type:
alert( !!"non-empty string" ); // true
alert( !!null ); // false
That is, the first NOT converts the value to boolean and returns the inverse, and the second NOT inverses it again. In the end, we have a plain value-to-boolean conversion.
The precedence of NOT ! is the highest of all logical operators, so it always executes first, before && or ||.
We have 3 type of loops:
The “while” loop
Example:
while (condition) {
// code
// so-called "loop body"
}
While the condition is true, the code from the loop body is executed. A single execution of the loop body is called an iteration. Any expression or variable can be a loop condition, not just comparisons: the condition is evaluated and converted to a boolean by while.
For instance, a shorter way to write while (i != 0) is while (i):
let i = 3;
while (i) { // when i becomes 0, the condition becomes falsy, and the loop stops
alert( i );
i--;
}
The “do…while” loop
“do…while” loop first will execute the body and then check the condition,and, while it’s truthy, execute it again and again Example:
let i = 0;
do {
alert( i );
i++;
} while (i < 3);
This form of syntax should only be used when you want the body of the loop to execute at least once regardless of the condition being truthy. Usually, the other form is preferred: while(…) {…}.
The “for” loop
The for loop is the most commonly used loop. Example:
for (begin; condition; step) {
// ... loop body ...
}
algoritm of this loop: Run begin
// for (let i = 0; i < 3; i++) alert(i)
// run begin let i = 0 // if condition → run body and run step if (i < 3) { alert(i); i++ } // if condition → run body and run step if (i < 3) { alert(i); i++ } // if condition → run body and run step if (i < 3) { alert(i); i++ } // ...finish, because now i == 3
Inline variable declaration
Example:
```(javascript)
for (let i = 0; i < 3; i++) {
alert(i); // 0, 1, 2
}
alert(i); // error, no such variable
Here, the “counter” variable i is declared right in the loop. This is called an “inline” variable declaration. Such variables are visible only inside the loop. So there is 2 type of variable:
Skipping parts We can skip any part of for. For example, we can omit begin if we don’t need to do anything at the loop start:
let i = 0; // we have i already declared and assigned
for (; i < 3; i++) { // no need for "begin"
alert( i ); // 0, 1, 2
}
Skip step:
let i = 0;
for (; i < 3;) {
alert( i++ );
}
This makes the loop identical to while (i < 3). We can actually remove everything, creating an infinite loop:
for (;;) {
// repeats without limits
}
!! Semicolons ; must be present or you will have syntax error.
Breaking the loop Normally, a loop exits when its condition becomes falsy. But we can force the exit at any time using the special break directive. Example:
let sum = 0;
while (true) {
let value = +prompt("Enter a number", '');
if (!value) break; // (*)
sum += value;
}
alert( 'Sum: ' + sum );
The break directive is activated at the line (*) if the user enters an empty line or cancels the input. It stops the loop immediately, passing control to the first line after the loop. Namely, alert. The combination “infinite loop + break as needed” is great for situations when a loop’s condition must be checked not in the beginning or end of the loop, but in the middle or even in several places of its body.
Continue to the next iteration The continue directive is a “lighter version” of break. It doesn’t stop the whole loop. Instead, it stops the current iteration and forces the loop to start a new one (if the condition allows).
We can use it if we’re done with the current iteration and would like to move on to the next one.
The loop below uses continue to output only odd values: 1st variant:
for (let i = 0; i < 10; i++) {
// if true, skip the remaining part of the body
if (i % 2 == 0) continue;
alert(i); // 1, then 3, 5, 7, 9
}
2nd variant:
for (let i = 0; i < 10; i++) {
if (i % 2) {
alert( i );
}
}
There is no differnce beetwen first and second variant, but first variant easy(easy understand or better readability) then second, because second use "{}" brace and there cab be alot of this, so better use first varian for easy read.
!!! No break/continue to the right side of ‘?’ Please note that syntax constructs that are not expressions cannot be used with the ternary operator ?. In particular, directives such as break/continue aren’t allowed there. Example:
if (i > 5) {
alert(i);
} else {
continue;
}
and if we use question mark "?" :
(i > 5) ? alert(i) : continue; // continue isn't allowed here
Code like this will have a syntax error: This is just another reason not to use the question mark operator ? instead of if.
Labels for break/continue Sometimes we need to break out from multiple nested loops at once. And for this manipulation we will use "Labels"; Example:
labelName: for (...) {
...
}
Exanple in code:
outer: for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
let input = prompt(`Value at coords (${i},${j})`, '');
// if an empty string or canceled, then break out of both loops
if (!input) break outer; // (*)
// do something with the value...
}
}
alert('Done!');
So, break outer will breal geleral(global) loops from coomand inside of any loops. Example:
loop1: for (begin,condition,step) { //first loop
for (begin,condotion,tep) { // second loop in the first loop
body //body of loop
if (!body) break loop1;
do something with the value
}
}
We also can have label into a separate lines:
loop1:
for (let i = 0; i < 3; i++) { ... }
To make an “infinite” loop, usually the while(true) construct is used. Such a loop, just like any other, can be stopped with the break directive.
If we don’t want to do anything in the current iteration and would like to forward to the next one, we can use the continue directive.
A switch statement can replace multiple if checks. It gives a more descriptive way to compare a value with multiple variants.
Example :
switch(x) {
case 'value1': // if (x === 'value1')
...
[break]
case 'value2': // if (x === 'value2')
...
[break]
default:
...
[break]
}
The value of x is checked for a strict equality to the value from the first case (that is, value1) then to the second (value2) and so on. If the equality is found, switch starts to execute the code starting from the corresponding case, until the nearest break (or until the end of switch). If no case is matched then the default code is executed (if it exists).
If there is no break then the execution continues with the next case without any checks:
let a = 2 + 2;
switch (a) {
case 3:
alert( 'Too small' );
case 4:
alert( 'Exactly!' );
case 5:
alert( 'Too big' );
default:
alert( "I don't know such values" );
}
So, in this example execution starts from 4(skip 3 because a=4 -> execution start from cas '4'), end we will see 3 results:
(javascript) alert( 'Exactly!' ); alert( 'Too big' ); alert( "I don't know such values" );
Any expression can be a switch/case argument:
```(javascript)
let a = "1";
let b = 0;
switch (+a) {
case b + 1:
alert("this runs, because +a is 1, exactly equals b+1");
break;
default:
alert("this doesn't run");
}
Here +a gives 1, that’s compared with b + 1 in case, and the corresponding code is executed.
Grouping of “case”
We can group any cases if they hhave same execution
Example:
let a = 2 + 2;
switch (a) {
case 4:
alert('Right!');
break;
case 3: // (*) grouped two cases
case 5:
alert('Wrong!');
alert("Why don't you take a math class?");
break;
default:
alert('The result is strange. Really.');
}
So, if we run case 3 and or case 5 we will have same execution.
Type matters:
The values must be of the same type to match. If not - then execute 'default'.
If we need use action many time in many places - we use Functions.
To create a function we can use a function declaration:
function nameFunction(parameters) {
the function body
}
Local variable - variable that created in function and this variable can be used only in this function, outside this function this variable is not working.
Outer variables - variable created outside of function and can be used at any function(global variable). Global variables are visible from any function (unless shadowed by locals). Usually, a function declares all variables specific to its task. Global variables only store project-level data, and it’s important that these variables are accessible from anywhere. Modern code has few or no globals. Most variables reside in their functions.
We can pass arbitrary data to functions using parameters (also called function arguments) . Example:
function showMessage(from, text) { // arguments: from, text
alert(from + ': ' + text);
}
showMessage('Ann', 'Hello!'); // Ann: Hello! (*)
showMessage('Ann', "What's up?"); // Ann: What's up? (**)
Parameters - it's like variable, but temporary.
Here’s one more example: we have a variable from and pass it to the function. Please note: the function changes from, but the change is not seen outside, because a function always gets a copy of the value:
function showMessage(from, text) {
from = '*' + from + '*'; // make "from" look nicer
alert( from + ': ' + text );
}
let from = "Ann";
showMessage(from, "Hello"); // *Ann*: Hello
// the value of "from" is the same, the function modified a local copy
alert( from ); // Ann
This example show how works global and local parameters(variable) in function
A function can return a value back into the calling code as the result:
function sum(a, b) {
return a + b;
}
let result = sum(1, 2);
alert( result ); // 3
Return can be placed in any place, when execution reaches it, the function stops and the value is returned to the calling code. There may be many occerences of return in a single function. Example:
function checkAge(age) {
if (age > 18) {
return true;
} else {
return confirm('Do you have permission from your parents?');
}
}
let age = prompt('How old are you?', 18);
if ( checkAge(age) ) {
alert( 'Access granted' );
} else {
alert( 'Access denied' );
}
It is possible to use return without a value. That causes the function to exit immediately.
For example:
function showMovie(age) {
if ( !checkAge(age) ) {
return;
}
alert( "Showing you the movie" ); // (*)
// ...
}
In the code above, if checkAge(age) returns false, then showMovie won’t proceed to the alert.
If a function does not return a value, it is the same as if it returns undefined:
function doNothing() { /* empty */ }
alert( doNothing() === undefined ); // true
An empty return is also the same as return undefined:
function doNothing() {
return;
}
alert( doNothing() === undefined ); // true
The syntax of Function Declaration:
function sayHi() { alert( "Hello" ); }
There is another syntax for creating a function that is called a Function Expression.
It looks like this:
let sayHi = function() { alert( "Hello" ); };
Copy functions to another variable:
function sayHi() { // (1) create
alert( "Hello" );
}
let func = sayHi; // (2) copy
func(); // Hello // (3) run the copy (it works)!
sayHi(); // Hello // this still works too (why wouldn't it)
What happens:
The Function Declaration (1) creates the function and puts it into the variable named sayHi.
Line (2) copies it into the variable func.
Please note again: there are no parentheses after sayHi. If there were, then func = sayHi() would write the result of the call sayHi() into func, not the function sayHi itself.
Now the function can be called as both sayHi() and func().
Note:
By syntax Function Expression have a semicolon ;
but Function Declaration does not.
We’ll write a function ask(question, yes, no) with three parameters:
question Text of the question yes Function to run if the answer is “Yes” no Function to run if the answer is “No”
The function should ask the question and, depending on the user’s answer, call yes() or no():
function ask(question, yes, no) {
if (confirm(question)) yes()
else no();
}
function showOk() {
alert( "You agreed." );
}
function showCancel() {
alert( "You canceled the execution." );
}
// usage: functions showOk, showCancel are passed as arguments to ask
ask("Do you agree?", showOk, showCancel);
We can use Function Expressions to write the same function much shorter:
function ask(question, yes, no) {
if (confirm(question)) yes()
else no();
}
ask(
"Do you agree?",
function() { alert("You agreed."); },
function() { alert("You canceled the execution."); }
);```
###A function is a value representing an “action”
Regular values like strings or numbers represent the data.
A function can be perceived as an action.
We can pass it between variables and run when we want.
##Function Expression vs Function Declaration
Function Declaration: a function, declared as a separate statement, in the main code flow.
Function Declaration:
```(javascript)
function sum(a, b) {
return a + b;
}
Function Expression: a function, created inside an expression or inside another syntax construct. Here, the function is created at the right side of the “assignment expression” =:
Function Expression:
let sum = function(a, b) {
return a + b;
};
A Function Expression is created when the execution reaches it and is usable from then on.
Once the execution flow passes to the right side of the assignment let sum = function… – here we go, the function is created and can be used (assigned, called, etc. ) from now on.
Function Declarations are different.
A Function Declaration is usable in the whole script/code block.
In other words, when JavaScript prepares to run the script or a code block, it first looks for Function Declarations in it and creates the functions. We can think of it as an “initialization stage”.
And after all of the Function Declarations are processed, the execution goes on.
As a result, a function declared as a Function Declaration can be called earlier than it is defined.
For example, this works:
sayHi("John"); // Hello, John
function sayHi(name) {
alert( `Hello, ${name}` );
}
The Function Declaration sayHi is created when JavaScript is preparing to start the script and is visible everywhere in it.
…If it was a Function Expression, then it wouldn’t work:
sayHi("John"); // error!
let sayHi = function(name) { // (*) no magic any more
alert( `Hello, ${name}` );
};
Function Expressions are created when the execution reaches them. That would happen only in the line (*). Too late.
In general we use Declaration fucntion because it much easy read and we need declare a function.
let func = (arg1, arg2, ...argN) => expression
This creates a function func that has arguments arg1..argN, evaluates the expression on the right side with their use and returns its result.
In other words, it’s roughly the same as:
let func = function(arg1, arg2, ...argN) {
return expression;
};
let sum = (a, b) => a + b;
/* The arrow function is a shorter form of:
let sum = function(a, b) {
return a + b;
};
*/
alert( sum(1, 2) ); // 3
If we have only one argument, then parentheses can be omitted, making that even shorter:
// same as
// let double = function(n) { return n * 2 }
let double = n => n * 2;
alert( double(3) ); // 6
If there are no arguments, parentheses should be empty (but they should be present):
let sayHi = () => alert("Hello!");
sayHi();
example arrow function:
let age = prompt("What is your age?", 18);
let welcome = (age < 18) ?
() => alert('Hello') :
() => alert("Greetings!");
welcome(); // ok now
In multiline arrow function we need use curly braces:
let sum = (a, b) => { // the curly brace opens a multiline function
let result = a + b;
return result; // if we use curly braces, use return to get results
};
alert( sum(1, 2) ); // 3
For creating objects we use {..}, example of empty Objects:
let user = new Object(); // "object constructor" syntax
let user = {}; // "object literal" syntax
That declaration is called an object literal.
We can immediately put some properties into {...} as “key: value” pairs:
let user = { // an object
name: "John", // by key "name" store value "John"
age: 30 // by key "age" store value 30
};
For get accesible to value of objects we use dot notation:
// get fields of the object:
alert( user.name ); // John
alert( user.age ); // 30
For multiword properties, the dot access doesn’t work:
// this would give a syntax error
user.likes birds = true
That’s because the dot requires the key to be a valid variable identifier. That is: no spaces and other limitations.
Square brackets also provide a way to obtain the property name as the result of any expression – as opposed to a literal string – like from a variable as follows:
let key = "likes birds";
// same as user["likes birds"] = true;
user[key] = true;
Example of square brackets:
let user = {
name: "John",
age: 30
};
let key = prompt("What do you want to know about the user?", "name");
// access by variable
alert( user[key] ); // John (if enter "name")
We can use square brackets in an object literal. That’s called computed properties:
let fruit = prompt("Which fruit to buy?", "apple");
let bag = {
[fruit]: 5, // the name of the property is taken from the variable fruit
};
alert( bag.apple ); // 5 if fruit="apple"
The meaning of a computed property is simple: [fruit] means that the property name should be taken from fruit.
So, if a visitor enters "apple", bag will become {apple: 5}. Same as:
let fruit = prompt("Which fruit to buy?", "apple");
let bag = {};
// take property name from the fruit variable
bag[fruit] = 5;
We can use more complex expressions inside square brackets:
let fruit = 'apple';
let bag = {
[fruit + 'Computers']: 5 // bag.appleComputers = 5
};
In real code we often use existing variables as values for property names:
function makeUser(name, age) {
return {
name: name,
age: age
// ...other properties
};
}
let user = makeUser("John", 30);
alert(user.name); // John
In the example above, properties have the same names as variables. The use-case of making a property from a variable is so common, that there’s a special property value shorthand to make it shorter.
Instead of name:name we can just write name, like this:
function makeUser(name, age) {
return {
name, // same as name: name
age // same as age: age
// ...
};
}
We can use both normal properties and shorthands in the same object:
let user = {
name, // same as name:name
age: 30
};
A notable objects feature is that it’s possible to access any property. There will be no error if the property doesn’t exist! Accessing a non-existing property just returns undefined. It provides a very common way to test whether the property exists – to get it and compare vs undefined:
let user = {};
alert( user.noSuchProperty === undefined ); // true means "no such property"
There is a special operator to check existence of a property "in" (instead of "... === undefined" ):
let user = { name: "John", age: 30 };
alert( "age" in user ); // true, user.age exists
alert( "blabla" in user ); // false, user.blabla doesn't exist
On the left side must be a property name. That’s usually a quoted string. But if we omit quotes then its mean that a variable containing the actual name will be tested. So if we skip quotes, we will check if on this variable have value that contained on this objects:
let user = { age: 30 };
let key = "age";
alert( key in user ); // true, takes the name from key and checks for such property
To walk over all keys of an object, there exists a special form of the loop: for..in. This is a completely different thing from the for(;;) construct that we studied before. The syntax:
for (key in object) {
// executes the body for each key among object properties
}
Example:
let user = {
name: "John",
age: 30,
isAdmin: true
};
for (let key in user) {
// keys
alert( key ); // name, age, isAdmin
// values for the keys
alert( user[key] ); // John, 30, true
}
Note that all “for” constructs allow us to declare the looping variable inside the loop, like let key here.
Also, we could use another variable name here instead of key. For instance, "for (let prop in obj)" is also widely used.
Are objects ordered? In other words, if we loop over an object, do we get all properties in the same order they were added? Can we rely on this?
The short answer is: “ordered in a special fashion”: integer properties are sorted, others appear in creation order. The details follow.
let codes = {
"49": "Germany",
"41": "Switzerland",
"44": "Great Britain",
// ..,
"1": "USA"
};
for (let code in codes) {
alert(code); // 1, 41, 44, 49
}
The phone codes go in the ascending sorted order, because they are integers. So we see 1, 41, 44, 49.
The “integer property” term here means a string that can be converted to-and-from an integer without a change.
// Math.trunc is a built-in function that removes the decimal part
alert( String(Math.trunc(Number("49"))) ); // "49", same, integer property
alert( String(Math.trunc(Number("+49"))) ); // "49", not same "+49" ⇒ not integer property
alert( String(Math.trunc(Number("1.2"))) ); // "1", not same "1.2" ⇒ not integer property
…On the other hand, if the keys are non-integer, then they are listed in the creation order, for instance:
let user = {
name: "John",
surname: "Smith"
};
user.age = 25; // add one more
// non-integer properties are listed in the creation order
for (let prop in user) {
alert( prop ); // name, surname, age
}
So if we add a plus "+" sign before each code it will be not sorted:
let codes = {
"+49": "Germany",
"+41": "Switzerland",
"+44": "Great Britain",
// ..,
"+1": "USA"
};
for (let code in codes) {
alert( +code ); // 49, 41, 44, 1
}
One of the fundamental differences of objects vs primitives is that they are stored and copied “by reference”. Primitive values: strings, numbers, booleans – are assigned/copied “as a whole value”. So, if we copy variable - it will be save new value. But if we copy object - it will just give acces to this "value" for another object. Variable: Here pharse = "Hello", if we change prhare value - message value are not chage, and we if chage message value - phrase value not changed.
let message = "Hello!";
let phrase = message;
Object: When an object variable is copied – the reference is copied, the object is not duplicated. If we imagine an object as a cabinet, then a variable is a key to it. Copying a variable duplicates the key, but not the cabinet itself.
So if we copy object1 to object2 then we just get acces to same value for object1 and object2, and if we change sometihng in object1 it will be changed in object2 also.
let user = { name: 'John' };
let admin = user;
admin.name = 'Pete'; // changed by the "admin" reference
alert(user.name); // 'Pete', changes are seen from the "user" reference
The example above demonstrates that there is only one object. As if we had a cabinet with two keys and used one of them (admin) to get into it. Then, if we later use the other key (user) we would see changes.
It means that we have only one object with 2 different name and with one common value.
The equality == and strict equality === operators for objects work exactly the same.
Two objects are equal only if they are the same object.
For instance, two variables reference the same object, they are equal:
let a = {};
let b = a; // copy the reference
alert( a == b ); // true, both variables reference the same object
alert( a === b ); // true
And here two independent objects are not equal, even though both are empty:
let a = {};
let b = {}; // two independent objects
alert( a == b ); // false
For comparisons like obj1 > obj2 or for a comparison against a primitive obj == 5, objects are converted to primitives. We’ll study how object conversions work very soon, but to tell the truth, such comparisons are necessary very rarely and usually are a result of a coding mistake.
An object declared as const can be changed.
const user = {
name: "John"
};
user.age = 25; // (*)
alert(user.age); // 25
It's not error, because we dont change any property of user, we just add new. But if we try change - we will see error:
const user = {
name: "John"
};
// Error (can't reassign user)
user = {
name: "Pete"
};
Somethimes we need copy object with all properies instead of a just link. Need to create new object and then copy property from another onbject:
let user = {
name: "John",
age: 30
};
let clone = {}; // the new empty object
// let's copy all user properties into it
for (let key in user) {
clone[key] = user[key];
}
// now clone is a fully independent clone
clone.name = "Pete"; // changed the data in it
alert( user.name ); // still John in the original object
Also we can use the method Object.assign for that.
The syntax is:
Object.assign(dest[, src1, src2, src3...])
Arguments dest, and src1, ..., srcN (can be as many as needed) are objects. It copies the properties of all objects src1, ..., srcN into dest. In other words, properties of all arguments starting from the 2nd are copied into the 1st. Then it returns dest.
For instance, we can use it to merge several objects into one:
let user = { name: "John" };
let permissions1 = { canView: true };
let permissions2 = { canEdit: true };
// copies all properties from permissions1 and permissions2 into user
Object.assign(user, permissions1, permissions2);
// now user = { name: "John", canView: true, canEdit: true }
If the receiving object (user) already has the same named property, it will be overwritten:
let user = { name: "John" };
// overwrite name, add isAdmin
Object.assign(user, { name: "Pete", isAdmin: true });
// now user = { name: "Pete", isAdmin: true }
We also can use Object.assign to replace the loop for simple cloning:
let user = {
name: "John",
age: 30
};
let clone = Object.assign({}, user);
It copies all properties of user into the empty object and returns it. Actually, the same as the loop, but shorter.
Now it’s not enough to copy clone.sizes = user.sizes, because the user.sizes is an object, it will be copied by reference. So clone and user will share the same sizes:
let user = {
name: "John",
sizes: {
height: 182,
width: 50
}
};
let clone = Object.assign({}, user);
alert( user.sizes === clone.sizes ); // true, same object
// user and clone share sizes
user.sizes.width++; // change a property from one place
alert(clone.sizes.width); // 51, see the result from the other one
To fix that, we should use the cloning loop that examines each value of user[key] and, if it’s an object, then replicate its structure as well. That is called a “deep cloning”.
There’s a standard algorithm for deep cloning that handles the case above and more complex cases, called the Structured cloning algorithm. In order not to reinvent the wheel, we can use a working implementation of it from the JavaScript library lodash, the method is called _.cloneDeep(obj).
To access a property, we can use: The dot notation: obj.property. Square brackets notation obj["property"]. Square brackets allow to take the key from a variable, like obj[varWithKey]. Additional operators: To delete a property: delete obj.prop. To check if a property with the given key exists: "key" in obj. To iterate over an object: for (let key in obj) loop.
To make a “real copy” (a clone) we can use Object.assign or _.cloneDeep(obj).
Javascript have garbage collection. Simple example:
let user = {
name: "John"
};
If we delete user, then proparty name will be also automatical deleted.
~~!!!(need create note ablut Symbol() ) #Symbol Symbol is a primitive tupe for unique identifiers and created by Sybmol() with an optional description. Symbols don’t auto-convert to a string
let id = Symbol("id");
alert(id); // TypeError: Cannot convert a Symbol value to a string
If functino sored in the object it's called method.
Methods allow objects to “act” like object.doSomething().
Methods can reference the object as this.
When a function is called in the “method” syntax: object.method(), the value of this during the call is object.
Arrow functions are special: they have no this. When this is accessed inside an arrow function, it is taken from outside.
To access the object, a method we can use the this keyword. Example:
let user = {
name: "John",
age: 30,
sayHi() {
alert(this.name);
}
};
user.sayHi(); // John
So this call the mail/global name of the object/etc.. . We use this becase name of variable can be changed while machine do our code, that's why we prefer to use this.
One function can have different this :
let user = { name: "John" };
let admin = { name: "Admin" };
function sayHi() {
alert( this.name );
}
// use the same functions in two objects
user.f = sayHi;
admin.f = sayHi;
// these calls have different this
// "this" inside the function is the object "before the dot"
user.f(); // John (this == user)
admin.f(); // Admin (this == admin)
admin['f'](); // Admin (dot or square brackets access the method – doesn't matter)
also, we can call function without an object:
function sayHi() {
alert(this);
}
sayHi(); // undefined