Галоўная > Разбор пытанняў з рэальных сумоўяў - 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 асяроддзі?

text
1let c = 1;
2function a(func) {
3  let c = 2;
4  func();
5}
6function b() {
7  console.log(c);
8}
9a(b);

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

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

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

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

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

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

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

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

text
1let a = 'a';
2function f(a) {
3  let b = 'b';
4  ...
5}
6f(a); // 1 выклік
7a = 'aa';
8f(a); // 2 выклік

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

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

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

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

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

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

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

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