Разбор пытанняў з рэальных сумоўяў - JS Core. Lexical scoping, Lexical Environment
Пытанне:
Што такое лексічнае асяроддзе (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
Каментары
(Каб даслаць каментар залагуйцеся ў свой уліковы запіс)