ինչ է Hoisting ը JavaScript-ում
Tags: javascript, webdev, programming
Published: 2024-01-03 09:36:42

այսպիսով javascript engine ը ունի առաջին հայացքից մի փոքր տարօրինակ բայց հետաքրքիր վարքագիծ այն փոփոխակաները class-ները function-ները բարձրացնում է  տվիալ scop-ի ամենավերևը դա տեղի է ունենում compilation ի փուլում և կոչվում է hoisting այն օգտակար է բայց եթե չգիտես ինչպես է աշխատում կարող խնդիրներ առաջացնել

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3tw4a5zl8o6dwexrfncw.png)


## Function Hoisting

```
function printHello() {
  console.log("hello")
}

printHello()
// hello
```
Այստեղ մենք հայտարարում ենք printHello ֆունկցիան և անմիջապես հետո կանչում այդ ֆունկցիան: Սխալներ չկան ամեն ինչ աշխատում է!

Այժմ նայեք այս օրինակին.

```
printHello()
// hello

function printHello() {
  console.log("hello")
}
```
հմմ Այստեղ մենք կանչում ենք printHello ֆունկցիան նախքան այն հայտարարելը: Եվ ամեն ինչ դեռ աշխատում է առանց սխալների: Ի՞նչ է տեղի ունեցել այստեղ։ hoisting .

Նախքան interpreter-ը կկատարի կոդը, այն նախ բարձրացնում է հայտարարված ֆունկցիաները scop-ի ամենավերևը(այն scop-ի որում ֆունկցիան հայտարարված է)։ hoistion-ի միջոցով ֆունկցիան հասանելի է դառնում նույնիսկ նախքան հայտարարելը։

Տեսնենք մեկ այլ օրինակ.

```
printHello()
// hello

printWorld()
// ReferenceError: printWorld is not defined

function printHello() {
  console.log('hello')

  function printWorld() {
    console.log("world")
  }
}
```
Ինչպես տեսնում եք այստեղ, մենք հայտարարում ենք printHello ֆունկցիան. որը տպում է 'hello' այնուհետև հայտարարում ենք մեկ այլ ֆունկցիա, որը կոչվում է printWorld, որը տպում է 'world' , երբ կանչվում է:

Նախքան printHello ֆուկցիան հայտարարելը, մենք փորձում ենք կանչել այն՝ printHello(). և Այն հասանելի է (ի շնորհիվ hoisting ի այն բարձրացել է global scop ի ամենավերևը), ուստի մենք «hello» ենք տեսնում console-ում:

Բայց հետո մենք կանչում ենք printWorld-ը, և ստանում ենք ReferenceError. printWorld-ը սահմանված չէ : Արդյո՞ք hoisting ը տեղի չի ունենում printWorld ի դեպքում:

hoisting ը աշխատում է, բայց այն "բարձրացնում է" միայն այն scop ի վերին մաս, որտեղ հայտարարվել է ֆունկցիան տվիալ դեպքում printHello ֆունկցիայի սքոփի վերևը: Հետևաբար, այն հասանելի կլինի միայն այդ ֆունկցիայում: Եկեք թարմացնենք մեր կոդը.

```
printHello()
// hello

function printHello() {
  printWorld()
  // world

  console.log('hello')

  function printWorld() {
    console.log("world")
  }
}
```
Այժմ մենք կանչում ենք printWorld ֆունկցիան printHello ֆունկցիայի վերևում, բայց նախքան printWorld ը հայտարարելը և այն աշխատում է Քանի որ hoisting ը ֆունկցիան բարձրացնում է local scop ի վերևը, և մենք կարող ենք մուտք գործել այն նախքան հայտարարելը

hoisting-ը այս ամենը հնարավոր է դարձնում function declaration-ների համար: Բայց, հարկ է նաև նշել, որ այն չի աշխատի function expression-ների դեպքում:  դրա մասին կգրեմ մեկ այլ անգամ

Հիմա եկեք նայենք փոփոխականների hoisting ը:

## Variable Hoisting


Դուք կարող եք փոփոխականներ հայտարարել JavaScript-ում var, let, և const keyword-ներով: Եվ այս փոփոխականները կենթարկվեն hoisting-ի, բայց այլ կերպ: Սկսենք var-ից.

_var_

Նայեք այս օրինակին.

```
console.log(name)
// undefined

var name = "Dav"
```
Այստեղ մենք հայտարարում ենք name անունով փոփոխական, որի արժեքը «dav» է: Բայց երբ մենք փորձում ենք մուտք գործել փոփոխական նախքան այն հայտարարելը ոչ մի սխալ չենք ստանում: hoisting է տեղի ունեցել. name փոփոխականը "բարձրացվել է" ուստի թարգմանիչը «գիտի», որ կա փոփոխական, որը կոչվում է name: Եթե ​​թարգմանիչը չիմանար, դուք կստանաք անունը սահմանված չէ : Եկեք փորձենք.

```
console.log(name)
// ReferenceError: name is not defined

var myName = "Dav"
```
Մենք ունենք փոփոխական, որը կոչվում է, myName (ոչ թե name): և ստանում ենք «անունը սահմանված չէ» սխալ, երբ փորձում ենք
վերցնել name-ի արժեքը: Թարգմանիչը «չգիտի» այս փոփոխականի մասին։

Վերադառնալով վերը նշված մեր օրինակին.

```
console.log(name)
// undefined

var name = "Dav"
```
Թեև hoisting ը տեղի է ունեցել այստեղ, բայց nameո ի արժեքը որոշված ​​չէ, երբ մենք մուտք ենք գործում այն ​​նախքան հայտարարելը: եթե փոփոխականը հայտարարված է var ով հայտարարությունը բարձրացվում է, բայց իր default արժեքով` undefined: Փաստացի արժեքը փոխվում է, երբ հայտարարման տողը կատարվում է և այդ տողից հետո փոփոխականին մուտք գործելով՝ մենք ստանում ենք իրական արժեքը.

```
console.log(name)
// undefined

var name = "Dav"

console.log(name)
// Dav
```


Ենթադրենք, name ը հայտարարել ենք ֆունկցիայի մեջ.

```
print()

console.log(name)
// ReferenceError: name is not defined

function print() {
  var name = "Dav"
}
```

Այստեղ մենք ստանում ենք ReferenceError. անունը սահմանված չէ : Հիշեք, որ փոփոխականները բարձրացվում են, բայց միայն այն scop ի վերին մաս որտեղ նրանք հայտարարվել են: Այս դեպքում, name-ը հայտարարված է print ֆունկցիայում, այնպես որ այն կբարձրացվի այդ local scop-ի վերև: Փորձենք մուտք գործել այն ֆունկցիայում.

```
print()

function print() {
  console.log(name)
  // undefined

  var name = "dav"
}
```

Փորձելով մուտք գործել name ֆունկցիայում, թեև այն գտնվում է հայտարարման տողից վեր, մենք սխալ չենք ստանում: Դա պայմանավորված է նրանով որ name ը բարձրացված է(hoisting), բայց մի մոռացեք, որ իր default արժեքով` undefined:

_let_

Թեև let փոփոխականները  նույնպես ենթարկվում են hoisting ի, նրանք ունեն այլ վարքագիծ: Տեսնենք մի օրինակ.

```
console.log(name)
// ReferenceError: Cannot access 'name' before initialization

let name = "Dav"
```

Այստեղ մենք ստանում ենք ReferenceError. Հնարավոր չէ մուտք գործել «name» նախքան հայտարարելը : Նկատո՞ւմ եք, որ սխալն ասում է, որ name ը սահմանված չէ : Դա պայմանավորված է նրանով, որ թարգմանիչը «տեղյակ է» name փոփոխականի մասին, քանի որ փոփոխականը ենթարկվել է hoisting ի:

«Cannot access 'name' before initialization» տեղի է ունենում, քանի որ հայտարարված let փոփոխականները չունեն default արժեք, երբ ենթարկվում է hoisting-ի(բարձրացվում է): Ինչպես տեսանք var, փոփոխականներն ունեն default արժեք՝ undefined մինչդեռ let, փոփոխականները չեն 'սկզբնավորվում':

Փոփոխականները բարձրացվում են այն scop ի վերին մաս, որտեղ նրանք հայտարարված են (local կամ glbal), բայց հասանելի չեն, քանի որ չեն սկզբնավորվել: Այդ հատվածը կոչվում է Temporal Dead Zone(ժամանակավոր մեռյալ գոտի):

Դրանք կարող են հասանելի լինել միայն հայտարարման տողից հետո.

_const _

const ի դեպքում ամեն ինչ նույն է ինչ let ի դեպքում

console.log(name)
// ReferenceError: Cannot access 'name' before initialization

const name = "Dav"

_Class_

JavaScript-ի class-ները նույնպես բարձրացվում են(hoisting): Տեսնենք մի օրինակ.

```
const Dog = new Animal("jeko")
// ReferenceError: Cannot access 'Animal' before initialization

class Animal {
  constructor(name) {
    this.name = name
  }
}
```

Այստեղ մենք հայտարարում ենք class, որը կոչվում է Animal. Մենք փորձում ենք մուտք գործել այս class (ստեղծելով Dog օբյեկտ) նախքան այն հայտարարելը: Մենք ստանում . ReferenceError հնարավոր չէ մուտք գործել «Animal» նախքան սկզբնավորումը : Ի՞նչ է ձեզ հիշեցնում այս սխալը:

Ճիշտ այնպես, ինչպես let և constփոփոխականների դեպքում, class ները բարձրացվում են այն scop ի վերևում, որտեղ նրանք սահմանվել են, բայց անհասանելի են այնքան ժամանակ, քանի դեռ չեն սկզբնավորվել:

Եկեք թարմացնենք կոդը.
```
class Animal {
  constructor(name) {
    this.name = name
  }
}

const Dog = new Animal("jeko")

console.log(Dog)
// { name: 'jeko' }
```

Animal ը հայտարարելուց հետո այն դառնում է հասանելի, այնպես որ մենք կարող ենք ստեղծել Dog առանց սխալների:


և այսպես երբեմն կտեսնեք այսպիսի կոդ

՝՝՝
function1()
function2()
function3()

// lines of code
// lines of code

function function1() {...}
function function2() {...}
function function3() {...}
՝՝՝

այստեղ ֆունկցաները իրենց տրամաբանությամբ հայտարարված են ներգևում բայց օգտագործվում կոդի մեջ  ավելի վերև այն աշխատում է ի շնորհիվ hoisting ի իսկ փոփոխականների և class ների դեպքում ամեն ինչ այլ է