Галоўная > Разбор пытанняў з рэальных сумоўяў - JS Core. Lexical scoping, Lexical Environment

Разбор пытанняў з рэальных сумоўяў - JS Core. Lexical scoping, Lexical Environment

сумоўе js

Пытанне:

Што такое лексічнае асяроддзе (lexical environment) і лексічная вобласць бачнасці (lexical scoping)?

Кароткі адказ

Функцыі ў JS маюць лексічную вобласць бачнасці (lexical scoping). Гэта азначае статычную прывязку да месца народжання функцыі. Калі ў функцыі няма патрэбнай пераменнай, яна будзе шукацца ў месце народжання функцыі у знешнем для гэтай функцыі асяроддзі.

Лексічнае асяроддзе (lexical environment) ствараецца ў момант выкліка функцыі.

Лексічнае асяроддзе - гэта спецыяльны ўнутраны аб'ект, у якім запісаны ўсе уласныя пераменныя функцыі і спасылка на знешнюю вобласць бачнасці, адкуль можна атрымаць значэнні знешніх пераменных.

Падрабязны адказ

Існуюць 2 асяроддзя, у якіх можа выконвацца код:

  • лексічнае асяроддзе (статычнае асяроддзе)

  • дынамічнае асяроддзе

Калі гаворка заходзіць пра JS, маецца на ўвазе лексічнае асяроддзе (акрамя выпадкаў выкарыстоўвання eval і with).

Чым адрозніваюцца гэтыя 2 асяроддзі?

let c = 1;
function a(func) {
  let c = 2;
  func();
}
function b() {
  console.log(c);
}
a(b);

У прыкладзе вышэй з адной функцыі a выклікваецца другая b.

У выпадку дынамічнай вобласці бачнасці пераменная (у выпадку ае адсутнасці ў самой функцыі) будзе шукацца ў месцы выкліку. Гэта азначае, што значэнне пераменнай будзе залежыць ад месца выкліку, і ў выпадку нашага прыклада вышэй будзе роўным 2.

У выпадку лексічнай вобласці бачнасці значэнне пераменнай будзе ўзята з вобласці стварэння функцыі са значэннем, актуальным на момант выкліка функцыі. У выпадку прыклада вышэй пераменная с будзе мець значэнне 1.

Як стварэнне лексічнай вобласці бачнасці працуе "пад капотам"?

У момант стварэння любой функцыі таксама ствараецца схаваная ўласцівасць [[Environment]], якая змяшчае ў сабе спасылку на тое месца, дзе была створана (альбо null, калі функцыя створана у глабальным кантэксце).

У момант выкліка функцыі кожны раз ствараецца схаваны аб'ект LexicalEnvironment, у якім змяшчаюцца 2 уласцівасці:

  • EnvironmentRecord - аб'ект, у якім будуць змяшчацца ўсе лакальныя пераменныя, параметры функцыі, кантэкст.

  • outer - спасылка, значэнне якой запісваецца са схаванай ўласцівасці [[Environment]].

let a = 'a';
function f(a) {
  let b = 'b';
  ...
}
f(a); // 1 выклік
a = 'aa';
f(a); // 2 выклік

У момант першага выкліка ствараецца лексічнае акружэнне для функцыі f:

  LexicalEnvironment = {
    EnvironmentRecord: {
      a: 'a', // значэнне пераменнай a, актуальнай на момант выкліку функцыі
      b: 'b' // гэта ўласцівасць дадаецца не адразу, а ў ходзе выконвання кода функцыі
    },
    outer: null // функцыя створана ў глабальным кантэксце <global LexicalEnvironment>, таму мае значэнне null
  }

У момант другога выкліка ствараецца новае лексічнае асяроддзе для функцыі f:

  LexicalEnvironment = {
    EnvironmentRecord: {
      a: 'aа', // значэнне пераменнай a, актуальнай на момант выкліку функцыі
      b: 'b',
    },
    outer: null
  }

Калі па спасылцы outer будзем пераходзіць у знешняе асяроддзе да глабальнай вобласці бачнасці, але і там гэтая пераменная не будзе знойдзена, у строгім рэжыме ('strict mode') будзе памылка, у звычайным - неяўнае стварэнне такой пераменнай у глабальнай вобласці бачнасці.

Майце на ўвазе - значэнне пераменнай не абавязкова павінна стаяць перад вызначэннем функцыі:

function func() {
console.log(num);
}
let num = 1;
func();
// 1
loveJS, 2023-02-24
Каментары

    (Каб даслаць каментар залагуйцеся ў свой уліковы запіс)

    ;