Разбор пытанняў з рэальных сумоўяў - JS Core. Lexical scoping, Lexical Environment
Пытанне:
Што такое лексічнае асяроддзе (lexical environment) і лексічная вобласць бачнасці (lexical scoping)?
Кароткі адказ
Функцыі ў JS маюць лексічную вобласць бачнасці (lexical scoping). Гэта азначае статычную прывязку да месца народжання функцыі. Калі ў функцыі няма патрэбнай пераменнай, яна будзе шукацца ў месце народжання функцыі у знешнем для гэтай функцыі асяроддзі.
Лексічнае асяроддзе (lexical environment) ствараецца ў момант выкліка функцыі.
Лексічнае асяроддзе - гэта спецыяльны ўнутраны аб'ект, у якім запісаны ўсе уласныя пераменныя функцыі і спасылка на знешнюю вобласць бачнасці, адкуль можна атрымаць значэнні знешніх пераменных.
Падрабязны адказ
Існуюць 2 асяроддзя, у якіх можа выконвацца код:
-
лексічнае асяроддзе (статычнае асяроддзе)
-
дынамічнае асяроддзе
Калі гаворка заходзіць пра JS, маецца на ўвазе лексічнае асяроддзе (акрамя выпадкаў выкарыстоўвання eval і with).
Чым адрозніваюцца гэтыя 2 асяроддзі?
text1let 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]].
text1let a = 'a'; 2function f(a) { 3 let b = 'b'; 4 ... 5} 6f(a); // 1 выклік 7a = 'aa'; 8f(a); // 2 выклік
У момант першага выкліка ствараецца лексічнае акружэнне для функцыі f:
text1 LexicalEnvironment = { 2 EnvironmentRecord: { 3 a: 'a', // значэнне пераменнай a, актуальнай на момант выкліку функцыі 4 b: 'b' // гэта ўласцівасць дадаецца не адразу, а ў ходзе выконвання кода функцыі 5 }, 6 outer: null // функцыя створана ў глабальным кантэксце <global LexicalEnvironment>, таму мае значэнне null 7 }
У момант другога выкліка ствараецца новае лексічнае асяроддзе для функцыі f:
text1 LexicalEnvironment = { 2 EnvironmentRecord: { 3 a: 'aа', // значэнне пераменнай a, актуальнай на момант выкліку функцыі 4 b: 'b', 5 }, 6 outer: null 7 }
Калі па спасылцы outer будзем пераходзіць у знешняе асяроддзе да глабальнай вобласці бачнасці, але і там гэтая пераменная не будзе знойдзена, у строгім рэжыме ('strict mode') будзе памылка, у звычайным - неяўнае стварэнне такой пераменнай у глабальнай вобласці бачнасці.
Майце на ўвазе - значэнне пераменнай не абавязкова павінна стаяць перад вызначэннем функцыі:
text1function func() { 2console.log(num); 3} 4let num = 1; 5func(); 6// 1
Каментары
(Каб даслаць каментар залагуйцеся ў свой уліковы запіс)