Ð ÑÑой главе Ð¼Ñ Ð¿Ñодолжим ÑаÑÑмаÑÑиваÑÑ, как ÑабоÑаÑÑ Ð¿ÐµÑеменнÑе, и, как ÑледÑÑвие, познакомимÑÑ Ñ Ð·Ð°Ð¼ÑканиÑми. ÐÑ Ð³Ð»Ð¾Ð±Ð°Ð»Ñного обÑекÑа Ð¼Ñ Ð¿ÐµÑÐµÑ Ð¾Ð´Ð¸Ð¼ к ÑабоÑе внÑÑÑи ÑÑнкÑий.
ÐекÑиÑеÑкое окÑÑжение
ÐÑе пеÑеменнÑе внÑÑÑи ÑÑнкÑии â ÑÑо ÑвойÑÑва ÑпеÑиалÑного внÑÑÑеннего обÑекÑа LexicalEnvironment, коÑоÑÑй ÑоздаÑÑÑÑ Ð¿Ñи ÐµÑ Ð·Ð°Ð¿ÑÑке.
ÐÑ Ð±Ñдем назÑваÑÑ ÑÑÐ¾Ñ Ð¾Ð±ÑÐµÐºÑ Â«Ð»ÐµÐºÑиÑеÑкое окÑÑжение» или пÑоÑÑо «обÑÐµÐºÑ Ð¿ÐµÑеменнÑÑ Â».
ÐÑи запÑÑке ÑÑнкÑÐ¸Ñ ÑоздаÑÑ Ð¾Ð±ÑÐµÐºÑ LexicalEnvironment, запиÑÑÐ²Ð°ÐµÑ ÑÑда аÑгÑменÑÑ, ÑÑнкÑии и пеÑеменнÑе. ÐÑоÑеÑÑ Ð¸Ð½Ð¸ÑиализаÑии вÑполнÑеÑÑÑ Ð² Ñом же поÑÑдке, ÑÑо и Ð´Ð»Ñ Ð³Ð»Ð¾Ð±Ð°Ð»Ñного обÑекÑа, коÑоÑÑй, вообÑе говоÑÑ, ÑвлÑеÑÑÑ ÑаÑÑнÑм ÑлÑÑаем лекÑиÑеÑкого окÑÑжениÑ.
РоÑлиÑие Ð¾Ñ window, обÑÐµÐºÑ LexicalEnvironment ÑвлÑеÑÑÑ Ð²Ð½ÑÑÑенним, он ÑкÑÑÑ Ð¾Ñ Ð¿ÑÑмого доÑÑÑпа.
ÐÑимеÑ
ÐоÑмоÑÑим пÑимеÑ, ÑÑÐ¾Ð±Ñ Ð»ÑÑÑе понимаÑÑ, как ÑÑо ÑабоÑаеÑ:
function sayHi(name) {
var phrase = "ÐÑивеÑ, " + name;
alert( phrase );
}
sayHi('ÐаÑÑ');
ÐÑи вÑзове ÑÑнкÑии:
-
Ðо вÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð¿ÐµÑвой ÑÑÑоÑки ÐµÑ ÐºÐ¾Ð´Ð°, на ÑÑадии иниÑиализаÑии, инÑеÑпÑеÑаÑÐ¾Ñ ÑоздаÑÑ Ð¿ÑÑÑой обÑекÑ
LexicalEnvironmentи заполнÑÐµÑ ÐµÐ³Ð¾.Рданном ÑлÑÑае ÑÑда Ð¿Ð¾Ð¿Ð°Ð´Ð°ÐµÑ Ð°ÑгÑменÑ
nameи единÑÑÐ²ÐµÐ½Ð½Ð°Ñ Ð¿ÐµÑеменнаÑphrase:function sayHi(name) { // LexicalEnvironment = { name: 'ÐаÑÑ', phrase: undefined } var phrase = "ÐÑивеÑ, " + name; alert( phrase ); } sayHi('ÐаÑÑ'); -
ФÑнкÑÐ¸Ñ Ð²ÑполнÑеÑÑÑ.
Ðо вÑÐµÐ¼Ñ Ð²ÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð¿ÑоиÑÑ Ð¾Ð´Ð¸Ñ Ð¿ÑиÑвоение локалÑной пеÑеменной
phrase, Ñо еÑÑÑ, дÑÑгими Ñловами, пÑиÑвоение ÑвойÑÑвÑLexicalEnvironment.phraseнового знаÑениÑ:function sayHi(name) { // LexicalEnvironment = { name: 'ÐаÑÑ', phrase: undefined } var phrase = "ÐÑивеÑ, " + name; // LexicalEnvironment = { name: 'ÐаÑÑ', phrase: 'ÐÑивеÑ, ÐаÑÑ'} alert( phrase ); } sayHi('ÐаÑÑ'); -
РконÑе вÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ ÑÑнкÑии обÑÐµÐºÑ Ñ Ð¿ÐµÑеменнÑми обÑÑно вÑбÑаÑÑваеÑÑÑ Ð¸ памÑÑÑ Ð¾ÑиÑаеÑÑÑ. РпÑимеÑÐ°Ñ Ð²ÑÑе Ñак и пÑоиÑÑ Ð¾Ð´Ð¸Ñ. ЧеÑез некоÑоÑое вÑÐµÐ¼Ñ Ð¼Ñ ÑаÑÑмоÑÑим более ÑложнÑе ÑиÑÑаÑии, пÑи коÑоÑÑÑ Ð¾Ð±ÑÐµÐºÑ Ñ Ð¿ÐµÑеменнÑми ÑÐ¾Ñ ÑанÑеÑÑÑ Ð¸ поÑле завеÑÑÐµÐ½Ð¸Ñ ÑÑнкÑии.
ÐÑли поÑиÑаÑÑ ÑпеÑиÑикаÑÐ¸Ñ ECMA-262, Ñо Ð¼Ñ Ñвидим, ÑÑо ÑеÑÑ Ð¸Ð´ÑÑ Ð¾ двÑÑ
обÑекÑаÑ
: VariableEnvironment и LexicalEnvironment.
Ðо Ñам же замеÑено, ÑÑо в ÑеализаÑиÑÑ
ÑÑи два обÑекÑа могÑÑ Ð±ÑÑÑ Ð¾Ð±ÑединенÑ. Так ÑÑо Ð¼Ñ Ð¸Ð·Ð±ÐµÐ³Ð°ÐµÐ¼ лиÑниÑ
деÑалей и иÑполÑзÑем везде ÑеÑмин LexicalEnvironment, ÑÑо доÑÑаÑоÑно ÑоÑно позволÑÐµÑ Ð¾Ð¿Ð¸ÑаÑÑ Ð¿ÑоиÑÑ
одÑÑее.
Ðолее ÑоÑмалÑное опиÑание Ð½Ð°Ñ Ð¾Ð´Ð¸ÑÑÑ Ð² ÑпеÑиÑикаÑии ECMA-262, ÑекÑии 10.2-10.5 и 13.
ÐоÑÑÑп ко внеÑним пеÑеменнÑм
Ðз ÑÑнкÑии Ð¼Ñ Ð¼Ð¾Ð¶ÐµÐ¼ обÑаÑиÑÑÑÑ Ð½Ðµ ÑолÑко к локалÑной пеÑеменной, но и к внеÑней:
var userName = "ÐаÑÑ";
function sayHi() {
alert( userName ); // "ÐаÑÑ"
}
ÐнÑеÑпÑеÑаÑоÑ, пÑи доÑÑÑпе к пеÑеменной, ÑнаÑала пÑÑаеÑÑÑ Ð½Ð°Ð¹Ñи пеÑеменнÑÑ Ð² ÑекÑÑем LexicalEnvironment, а заÑем, еÑли ÐµÑ Ð½ÐµÑ â иÑÐµÑ Ð²Ð¾ внеÑнем обÑекÑе пеÑеменнÑÑ
. Рданном ÑлÑÑае им ÑвлÑеÑÑÑ window.
Такой поÑÑдок поиÑка возможен благодаÑÑ ÑомÑ, ÑÑо ÑÑÑлка на внеÑний обÑÐµÐºÑ Ð¿ÐµÑеменнÑÑ
Ñ
ÑаниÑÑÑ Ð² ÑпеÑиалÑном внÑÑÑеннем ÑвойÑÑве ÑÑнкÑии, коÑоÑое назÑваеÑÑÑ [[Scope]]. ÐÑо ÑвойÑÑво закÑÑÑо Ð¾Ñ Ð¿ÑÑмого доÑÑÑпа, но знание о нÑм оÑÐµÐ½Ñ Ð²Ð°Ð¶Ð½Ð¾ Ð´Ð»Ñ Ð¿Ð¾Ð½Ð¸Ð¼Ð°Ð½Ð¸Ñ Ñого, как ÑабоÑÐ°ÐµÑ JavaScript.
ÐÑи Ñоздании ÑÑнкÑÐ¸Ñ Ð¿Ð¾Ð»ÑÑÐ°ÐµÑ ÑкÑÑÑое ÑвойÑÑво [[Scope]], коÑоÑое ÑÑÑлаеÑÑÑ Ð½Ð° лекÑиÑеÑкое окÑÑжение, в коÑоÑом она бÑла Ñоздана.
РпÑимеÑе вÑÑе Ñаким окÑÑжением ÑвлÑеÑÑÑ window, Ñак ÑÑо ÑоздаÑÑÑÑ ÑвойÑÑво:
sayHi.[[Scope]] = window
ÐÑо ÑвойÑÑво никогда не менÑеÑÑÑ. Ðно вÑÑÐ´Ñ ÑледÑÐµÑ Ð·Ð° ÑÑнкÑией, пÑивÑзÑÐ²Ð°Ñ ÐµÑ, Ñаким обÑазом, к меÑÑÑ Ñвоего ÑождениÑ.
ÐÑи запÑÑке ÑÑнкÑии ÐµÑ Ð¾Ð±ÑÐµÐºÑ Ð¿ÐµÑеменнÑÑ
LexicalEnvironment полÑÑÐ°ÐµÑ ÑÑÑÐ»ÐºÑ Ð½Ð° «внеÑнее лекÑиÑеÑкое окÑÑжение» Ñо знаÑением из [[Scope]].
ÐÑли пеÑÐµÐ¼ÐµÐ½Ð½Ð°Ñ Ð½Ðµ найдена в ÑÑнкÑии â она бÑÐ´ÐµÑ Ð¸ÑкаÑÑÑÑ ÑнаÑÑжи.
Ðменно благодаÑÑ ÑÑой меÑ
анике в пÑимеÑе вÑÑе alert(userName) вÑÐ²Ð¾Ð´Ð¸Ñ Ð²Ð½ÐµÑнÑÑ Ð¿ÐµÑеменнÑÑ. Ðа ÑÑовне кода ÑÑо вÑглÑÐ´Ð¸Ñ ÐºÐ°Ðº поиÑк во внеÑней облаÑÑи видимоÑÑи, вне ÑÑнкÑии.
ÐÑли обобÑиÑÑ:
- ÐÐ°Ð¶Ð´Ð°Ñ ÑÑнкÑÐ¸Ñ Ð¿Ñи Ñоздании полÑÑÐ°ÐµÑ ÑÑÑлкÑ
[[Scope]]на обÑÐµÐºÑ Ñ Ð¿ÐµÑеменнÑми, в конÑекÑÑе коÑоÑого бÑла Ñоздана. - ÐÑи запÑÑке ÑÑнкÑии ÑоздаÑÑÑÑ Ð½Ð¾Ð²Ñй обÑÐµÐºÑ Ñ Ð¿ÐµÑеменнÑми
LexicalEnvironment. Ðн полÑÑÐ°ÐµÑ ÑÑÑÐ»ÐºÑ Ð½Ð° внеÑний обÑÐµÐºÑ Ð¿ÐµÑеменнÑÑ Ð¸Ð·[[Scope]]. - ÐÑи поиÑке пеÑеменнÑÑ Ð¾Ð½ оÑÑÑеÑÑвлÑеÑÑÑ ÑнаÑала в ÑекÑÑем обÑекÑе пеÑеменнÑÑ , а поÑом â по ÑÑой ÑÑÑлке.
ÐÑглÑÐ´Ð¸Ñ Ð½Ð°ÑÑолÑко пÑоÑÑо, ÑÑо непонÑÑно â заÑем вообÑе говоÑиÑÑ Ð¾Ð± ÑÑом [[Scope]], об обÑекÑаÑ
пеÑеменнÑÑ
. Сказали бÑ: «ФÑнкÑÐ¸Ñ ÑиÑÐ°ÐµÑ Ð¿ÐµÑеменнÑе ÑнаÑÑжи» â и вÑÑ. Ðо знание ÑÑиÑ
деÑалей Ð¿Ð¾Ð·Ð²Ð¾Ð»Ð¸Ñ Ð½Ð°Ð¼ легко обÑÑÑниÑÑ Ð¸ понÑÑÑ Ð±Ð¾Ð»ÐµÐµ ÑложнÑе ÑиÑÑаÑии, Ñ ÐºÐ¾ÑоÑÑми Ð¼Ñ ÑÑолкнÑмÑÑ Ð´Ð°Ð»ÐµÐµ.
ÐÑегда ÑекÑÑее знаÑение
ÐнаÑение пеÑеменной из внеÑней облаÑÑи беÑÑÑÑÑ Ð²Ñегда ÑекÑÑее. Ðно Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ñже не Ñо, ÑÑо бÑло на Ð¼Ð¾Ð¼ÐµÐ½Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ ÑÑнкÑии.
ÐапÑимеÑ, в коде ниже ÑÑнкÑÐ¸Ñ sayHi беÑÑÑ phrase из внеÑней облаÑÑи:
var phrase = 'ÐÑивеÑ';
function sayHi(name) {
alert(phrase + ', ' + name);
}
sayHi('ÐаÑÑ'); // ÐÑивеÑ, ÐаÑÑ (*)
phrase = 'Ðока';
sayHi('ÐаÑÑ'); // Ðока, ÐаÑÑ (**)
Ðа Ð¼Ð¾Ð¼ÐµÐ½Ñ Ð¿ÐµÑвого запÑÑка (*), пеÑÐµÐ¼ÐµÐ½Ð½Ð°Ñ phrase имела знаÑение 'ÐÑивеÑ', а ко вÑоÑÐ¾Ð¼Ñ (**) изменила его на 'Ðока'.
ÐÑо еÑÑеÑÑвенно, Ð²ÐµÐ´Ñ Ð´Ð»Ñ Ð´Ð¾ÑÑÑпа к внеÑней пеÑеменной ÑÑнкÑÐ¸Ñ Ð¿Ð¾ ÑÑÑлке [[Scope]] обÑаÑаеÑÑÑ Ð²Ð¾ внеÑний обÑÐµÐºÑ Ð¿ÐµÑеменнÑÑ
и беÑÑÑ Ñо знаÑение, коÑоÑое Ñам еÑÑÑ Ð½Ð° Ð¼Ð¾Ð¼ÐµÐ½Ñ Ð¾Ð±ÑаÑениÑ.
ÐложеннÑе ÑÑнкÑии
ÐнÑÑÑи ÑÑнкÑии можно обÑÑвлÑÑÑ Ð½Ðµ ÑолÑко локалÑнÑе пеÑеменнÑе, но и дÑÑгие ÑÑнкÑии.
РпÑимеÑÑ, Ð²Ð»Ð¾Ð¶ÐµÐ½Ð½Ð°Ñ ÑÑнкÑÐ¸Ñ Ð¼Ð¾Ð¶ÐµÑ Ð¿Ð¾Ð¼Ð¾ÑÑ Ð»ÑÑÑе оÑганизоваÑÑ ÐºÐ¾Ð´:
function sayHiBye(firstName, lastName) {
alert( "ÐÑивеÑ, " + getFullName() );
alert( "Ðока, " + getFullName() );
function getFullName() {
return firstName + " " + lastName;
}
}
sayHiBye("ÐаÑÑ", "ÐÑпкин"); // ÐÑивеÑ, ÐаÑÑ ÐÑпкин ; Ðока, ÐаÑÑ ÐÑпкин
ÐдеÑÑ, Ð´Ð»Ñ ÑдобÑÑва, Ñоздана вÑпомогаÑелÑÐ½Ð°Ñ ÑÑнкÑÐ¸Ñ getFullName().
ÐложеннÑе ÑÑнкÑии полÑÑаÑÑ [[Scope]] Ñак же, как и глобалÑнÑе. РнаÑем ÑлÑÑае:
getFullName.[[Scope]] = обÑÐµÐºÑ Ð¿ÐµÑеменнÑÑ
ÑекÑÑего запÑÑка sayHiBye
ÐлагодаÑÑ ÑÑÐ¾Ð¼Ñ getFullName() полÑÑÐ°ÐµÑ ÑнаÑÑжи firstName и lastName.
ÐамеÑим, ÑÑо еÑли пеÑÐµÐ¼ÐµÐ½Ð½Ð°Ñ Ð½Ðµ найдена во внеÑнем обÑекÑе пеÑеменнÑÑ
, Ñо она иÑеÑÑÑ Ð² еÑÑ Ð±Ð¾Ð»ÐµÐµ внеÑнем (ÑеÑез [[Scope]] внеÑней ÑÑнкÑии), Ñо еÑÑÑ, Ñакой пÑÐ¸Ð¼ÐµÑ Ñоже бÑÐ´ÐµÑ ÑабоÑаÑÑ:
var phrase = 'ÐÑивеÑ';
function say() {
function go() {
alert( phrase ); // найдÑÑ Ð¿ÐµÑеменнÑÑ ÑнаÑÑжи
}
go();
}
say();
ÐозвÑÐ°Ñ ÑÑнкÑии
РаÑÑмоÑÑим более «пÑодвинÑÑÑй» ваÑианÑ, пÑи коÑоÑом внÑÑÑи одной ÑÑнкÑии ÑоздаÑÑÑÑ Ð´ÑÑÐ³Ð°Ñ Ð¸ возвÑаÑаеÑÑÑ Ð² каÑеÑÑве ÑезÑлÑÑаÑа.
Ð ÑазÑабоÑке инÑеÑÑейÑов ÑÑо ÑовеÑÑенно ÑÑандаÑÑнÑй пÑиÑм, ÑÑнкÑÐ¸Ñ Ð·Ð°Ñем Ð¼Ð¾Ð¶ÐµÑ Ð½Ð°Ð·Ð½Ð°ÑаÑÑÑÑ ÐºÐ°Ðº обÑабоÑÑик дейÑÑвий поÑеÑиÑелÑ.
ÐдеÑÑ Ð¼Ñ Ð±Ñдем ÑоздаваÑÑ ÑÑнкÑиÑ-ÑÑÑÑÑик, коÑоÑÐ°Ñ ÑÑиÑÐ°ÐµÑ Ñвои вÑÐ·Ð¾Ð²Ñ Ð¸ возвÑаÑÐ°ÐµÑ Ð¸Ñ ÑекÑÑее ÑиÑло.
РпÑимеÑе ниже makeCounter ÑоздаÑÑ ÑакÑÑ ÑÑнкÑиÑ:
function makeCounter() {
var currentCount = 1;
return function() { // (**)
return currentCount++;
};
}
var counter = makeCounter(); // (*)
// каждÑй вÑзов ÑвелиÑÐ¸Ð²Ð°ÐµÑ ÑÑÑÑÑик и возвÑаÑÐ°ÐµÑ ÑезÑлÑÑаÑ
alert( counter() ); // 1
alert( counter() ); // 2
alert( counter() ); // 3
// ÑоздаÑÑ Ð´ÑÑгой ÑÑÑÑÑик, он бÑÐ´ÐµÑ Ð½ÐµÐ·Ð°Ð²Ð¸Ñим Ð¾Ñ Ð¿ÐµÑвого
var counter2 = makeCounter();
alert( counter2() ); // 1
Ðак видно, Ð¼Ñ Ð¿Ð¾Ð»ÑÑили два незавиÑимÑÑ
ÑÑÑÑÑика counter и counter2, каждÑй из коÑоÑÑÑ
незамеÑнÑм ÑнаÑÑжи обÑазом ÑоÑ
ÑанÑÐµÑ ÑекÑÑее колиÑеÑÑво вÑзовов.
Ðде? ÐонеÑно, во внеÑней пеÑеменной currentCount, коÑоÑÐ°Ñ Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ ÑÑÑÑÑика ÑвоÑ.
ÐÑли подÑобнее опиÑаÑÑ Ð¿ÑоиÑÑ Ð¾Ð´ÑÑее:
-
Ð ÑÑÑоке
(*)запÑÑкаеÑÑÑmakeCounter(). ÐÑи ÑÑом ÑоздаÑÑÑÑLexicalEnvironmentÐ´Ð»Ñ Ð¿ÐµÑеменнÑÑ ÑекÑÑего вÑзова. Ð ÑÑнкÑии еÑÑÑ Ð¾Ð´Ð½Ð° пеÑеменнаÑvar currentCount, коÑоÑÐ°Ñ ÑÑÐ°Ð½ÐµÑ ÑвойÑÑвом ÑÑого обÑекÑа. Ðна изнаÑалÑно иниÑиализÑеÑÑÑ Ð²undefined, заÑем, в пÑоÑеÑÑе вÑполнениÑ, полÑÑÐ¸Ñ Ð·Ð½Ð°Ñение1:function makeCounter() { // LexicalEnvironment = { currentCount: undefined } var currentCount = 1; // LexicalEnvironment = { currentCount: 1 } return function() { // [[Scope]] -> LexicalEnvironment (**) return currentCount++; }; } var counter = makeCounter(); // (*) -
РпÑоÑеÑÑе вÑполнениÑ
makeCounter()ÑоздаÑÑ ÑÑнкÑÐ¸Ñ Ð² ÑÑÑоке(**). ÐÑи Ñоздании ÑÑа ÑÑнкÑÐ¸Ñ Ð¿Ð¾Ð»ÑÑÐ°ÐµÑ Ð²Ð½ÑÑÑеннее ÑвойÑÑво[[Scope]]Ñо ÑÑÑлкой на ÑекÑÑийLexicalEnvironment. -
Ðалее вÑзов
makeCounter()завеÑÑаеÑÑÑ Ð¸ ÑÑнкÑиÑ(**)возвÑаÑаеÑÑÑ Ð¸ ÑÐ¾Ñ ÑанÑеÑÑÑ Ð²Ð¾ внеÑней пеÑеменнойcounter(*).
Ðа ÑÑом Ñоздание «ÑÑÑÑÑика» завеÑÑено.
ÐÑоговÑм знаÑением, запиÑаннÑм в пеÑеменнÑÑ counter, ÑвлÑеÑÑÑ ÑÑнкÑиÑ:
function() { // [[Scope]] -> {currentCount: 1}
return currentCount++;
};
ÐозвÑаÑÑÐ½Ð½Ð°Ñ Ð¸Ð· makeCounter() ÑÑнкÑÐ¸Ñ counter Ð¿Ð¾Ð¼Ð½Ð¸Ñ (ÑеÑез [[Scope]]) о Ñом, в каком окÑÑжении бÑла Ñоздана.
ÐÑо и иÑполÑзÑеÑÑÑ Ð´Ð»Ñ Ñ ÑÐ°Ð½ÐµÐ½Ð¸Ñ ÑекÑÑего знаÑÐµÐ½Ð¸Ñ ÑÑÑÑÑика.
Ðалее, когда-нибÑдÑ, ÑÑнкÑÐ¸Ñ counter бÑÐ´ÐµÑ Ð²Ñзвана. ÐÑ Ð½Ðµ знаем, когда ÑÑо пÑоизойдÑÑ. ÐÐ¾Ð¶ÐµÑ Ð±ÑÑÑ, пÑÑмо ÑейÑаÑ, но, вообÑе говоÑÑ, ÑовÑем не ÑакÑ.
ÐÑа ÑÑнкÑÐ¸Ñ ÑоÑÑÐ¾Ð¸Ñ Ð¸Ð· одной ÑÑÑоки: return currentCount++, ни пеÑеменнÑÑ
ни паÑамеÑÑов в ней неÑ, поÑÑÐ¾Ð¼Ñ ÐµÑ ÑобÑÑвеннÑй обÑÐµÐºÑ Ð¿ÐµÑеменнÑÑ
, Ð´Ð»Ñ ÐºÑаÑкоÑÑи назовÑм его LE â бÑÐ´ÐµÑ Ð¿ÑÑÑ.
Ðднако, Ñ Ð½ÐµÑ ÐµÑÑÑ ÑвойÑÑво [[Scope]], коÑоÑое ÑказÑÐ²Ð°ÐµÑ Ð½Ð° внеÑнее окÑÑжение. ЧÑÐ¾Ð±Ñ ÑвелиÑиÑÑ Ð¸ веÑнÑÑÑ currentCount, инÑеÑпÑеÑаÑÐ¾Ñ Ð¸ÑÐµÑ Ð² ÑекÑÑем обÑекÑе пеÑеменнÑÑ
LE, не наÑ
одиÑ, заÑем идÑÑ Ð²Ð¾ внеÑний обÑекÑ, Ñам наÑ
одиÑ, изменÑÐµÑ Ð¸ возвÑаÑÐ°ÐµÑ Ð½Ð¾Ð²Ð¾Ðµ знаÑение:
function makeCounter() {
var currentCount = 1;
return function() {
return currentCount++;
};
}
var counter = makeCounter(); // [[Scope]] -> {currentCount: 1}
alert( counter() ); // 1, [[Scope]] -> {currentCount: 1}
alert( counter() ); // 2, [[Scope]] -> {currentCount: 2}
alert( counter() ); // 3, [[Scope]] -> {currentCount: 3}
ÐеÑеменнÑÑ Ð²Ð¾ внеÑней облаÑÑи видимоÑÑи можно не ÑолÑко ÑиÑаÑÑ, но и изменÑÑÑ.
РпÑимеÑе вÑÑе бÑло Ñоздано неÑколÑко ÑÑÑÑÑиков. ÐÑе они взаимно незавиÑимÑ:
var counter = makeCounter();
var counter2 = makeCounter();
alert( counter() ); // 1
alert( counter() ); // 2
alert( counter() ); // 3
alert( counter2() ); // 1, ÑÑÑÑÑики незавиÑимÑ
Ðни незавиÑимÑ, поÑÐ¾Ð¼Ñ ÑÑо пÑи каждом запÑÑке makeCounter ÑоздаÑÑÑÑ Ñвой обÑÐµÐºÑ Ð¿ÐµÑеменнÑÑ
LexicalEnvironment, Ñо Ñвоим ÑвойÑÑвом currentCount, на коÑоÑÑй новÑй ÑÑÑÑÑик полÑÑÐ¸Ñ ÑÑÑÐ»ÐºÑ [[Scope]].
СвойÑÑва ÑÑнкÑии
ФÑнкÑÐ¸Ñ Ð² JavaScript ÑвлÑеÑÑÑ Ð¾Ð±ÑекÑом, поÑÑÐ¾Ð¼Ñ Ð¼Ð¾Ð¶Ð½Ð¾ пÑиÑваиваÑÑ ÑвойÑÑва пÑÑмо к ней, Ð²Ð¾Ñ Ñак:
function f() {}
f.test = 5;
alert( f.test );
СвойÑÑва ÑÑнкÑии не ÑÑÐ¾Ð¸Ñ Ð¿ÑÑаÑÑ Ñ Ð¿ÐµÑеменнÑми и паÑамеÑÑами. Ðни ÑовеÑÑенно никак не ÑвÑзанÑ. ÐеÑеменнÑе доÑÑÑÐ¿Ð½Ñ ÑолÑко внÑÑÑи ÑÑнкÑии, они ÑоздаÑÑÑÑ Ð² пÑоÑеÑÑе ÐµÑ Ð²ÑполнениÑ. ÐÑо â иÑполÑзование ÑÑнкÑии «как ÑÑнкÑии».
Ð ÑвойÑÑво Ñ ÑÑнкÑии â доÑÑÑпно оÑовÑÑÐ´Ñ Ð¸ вÑегда. ÐÑо â иÑполÑзование ÑÑнкÑии «как обÑекÑа».
ÐÑли Ñ Ð¾ÑеÑÑÑ Ð¿ÑивÑзаÑÑ Ð·Ð½Ð°Ñение к ÑÑнкÑии, Ñо можно им воÑполÑзоваÑÑÑÑ Ð²Ð¼ÐµÑÑо внеÑÐ½Ð¸Ñ Ð¿ÐµÑеменнÑÑ .
РкаÑеÑÑве демонÑÑÑаÑии, пеÑепиÑем пÑÐ¸Ð¼ÐµÑ Ñо ÑÑÑÑÑиком:
function makeCounter() {
function counter() {
return counter.currentCount++;
};
counter.currentCount = 1;
return counter;
}
var counter = makeCounter();
alert( counter() ); // 1
alert( counter() ); // 2
ÐÑи запÑÑке пÑÐ¸Ð¼ÐµÑ ÑабоÑÐ°ÐµÑ Ñакже.
ÐÑинÑипиалÑÐ½Ð°Ñ ÑазниÑа â во внÑÑÑенней Ð¼ÐµÑ Ð°Ð½Ð¸ÐºÐµ и в Ñом, ÑÑо ÑвойÑÑво ÑÑнкÑии, в оÑлиÑие Ð¾Ñ Ð¿ÐµÑеменной из замÑÐºÐ°Ð½Ð¸Ñ â обÑедоÑÑÑпно, к Ð½ÐµÐ¼Ñ Ð¸Ð¼ÐµÐµÑ Ð´Ð¾ÑÑÑп лÑбой, Ñ ÐºÐ¾Ð³Ð¾ еÑÑÑ Ð¾Ð±ÑÐµÐºÑ ÑÑнкÑии.
ÐапÑимеÑ, можно взÑÑÑ Ð¸ поменÑÑÑ ÑÑÑÑÑик из внеÑнего кода:
var counter = makeCounter();
alert( counter() ); // 1
counter.currentCount = 5;
alert( counter() ); // 5
Ðногда ÑвойÑÑва, пÑивÑзаннÑе к ÑÑнкÑии, назÑваÑÑ Â«ÑÑаÑиÑеÑкими пеÑеменнÑми».
РнекоÑоÑÑÑ ÑзÑÐºÐ°Ñ Ð¿ÑогÑаммиÑÐ¾Ð²Ð°Ð½Ð¸Ñ Ð¼Ð¾Ð¶Ð½Ð¾ обÑÑвлÑÑÑ Ð¿ÐµÑеменнÑÑ, коÑоÑÐ°Ñ ÑÐ¾Ñ ÑанÑÐµÑ Ð·Ð½Ð°Ñение Ð¼ÐµÐ¶Ð´Ñ Ð²Ñзовами ÑÑнкÑии. Ð JavaScript ближайÑий аналог â Ñакое Ð²Ð¾Ñ ÑвойÑÑво ÑÑнкÑии.
ÐÑого: замÑканиÑ
ÐамÑкание â ÑÑо ÑÑнкÑÐ¸Ñ Ð²Ð¼ÐµÑÑе Ñо вÑеми внеÑними пеÑеменнÑми, коÑоÑÑе ей доÑÑÑпнÑ.
Таково ÑÑандаÑÑное опÑеделение, коÑоÑое еÑÑÑ Ð² Wikipedia и болÑÑинÑÑве ÑеÑÑÑзнÑÑ Ð¸ÑÑоÑников по пÑогÑаммиÑованиÑ. То еÑÑÑ, замÑкание â ÑÑо ÑÑнкÑÐ¸Ñ + внеÑние пеÑеменнÑе.
Тем не менее, в JavaScript еÑÑÑ Ð½ÐµÐ±Ð¾Ð»ÑÑÐ°Ñ ÑеÑминологиÑеÑÐºÐ°Ñ Ð¾ÑобенноÑÑÑ.
ÐбÑÑно, говоÑÑ Â«Ð·Ð°Ð¼Ñкание ÑÑнкÑии», подÑазÑмеваÑÑ Ð½Ðµ ÑÐ°Ð¼Ñ ÑÑÑ ÑÑнкÑиÑ, а именно внеÑние пеÑеменнÑе.
Ðногда говоÑÑÑ Â«Ð¿ÐµÑÐµÐ¼ÐµÐ½Ð½Ð°Ñ Ð±ÐµÑÑÑÑÑ Ð¸Ð· замÑканиÑ». ÐÑо ознаÑÐ°ÐµÑ â из внеÑнего обÑекÑа пеÑеменнÑÑ .
Ðногда говоÑÑÑ Â«ÐаÑÑ Ð¼Ð¾Ð»Ð¾Ð´ÐµÑ, Ð¿Ð¾Ð½Ð¸Ð¼Ð°ÐµÑ Ð·Ð°Ð¼ÑканиÑ!». ЧÑо ÑÑо Ñакое â «понимаÑÑ Ð·Ð°Ð¼ÑканиÑ», какой ÑмÑÑл обÑÑно вкладÑваÑÑ Ð² ÑÑи Ñлова?
«ÐонимаÑÑ Ð·Ð°Ð¼ÑканиÑ» в JavaScript ознаÑÐ°ÐµÑ Ð¿Ð¾Ð½Ð¸Ð¼Ð°ÑÑ ÑледÑÑÑие веÑи:
- ÐÑе пеÑеменнÑе и паÑамеÑÑÑ ÑÑнкÑий ÑвлÑÑÑÑÑ ÑвойÑÑвами обÑекÑа пеÑеменнÑÑ
LexicalEnvironment. ÐаждÑй запÑÑк ÑÑнкÑии ÑоздаÑÑ Ð½Ð¾Ð²Ñй Ñакой обÑекÑ. Ðа веÑÑ Ð½ÐµÐ¼ ÑÑовне им ÑвлÑеÑÑÑ Â«Ð³Ð»Ð¾Ð±Ð°Ð»ÑнÑй обÑекÑ», в бÑаÑзеÑе âwindow. - ÐÑи Ñоздании ÑÑнкÑÐ¸Ñ Ð¿Ð¾Ð»ÑÑÐ°ÐµÑ ÑиÑÑемное ÑвойÑÑво
[[Scope]], коÑоÑое ÑÑÑлаеÑÑÑ Ð½Ð°LexicalEnvironment, в коÑоÑом она бÑла Ñоздана. - ÐÑи вÑзове ÑÑнкÑии, кÑда Ð±Ñ ÐµÑ Ð½Ð¸ пеÑедали в коде â она бÑÐ´ÐµÑ Ð¸ÑкаÑÑ Ð¿ÐµÑеменнÑе ÑнаÑала Ñ ÑебÑ, а заÑем во внеÑниÑ
LexicalEnvironmentÑ Ð¼ÐµÑÑа Ñвоего «ÑождениÑ».
Ð ÑледÑÑÑÐ¸Ñ Ð³Ð»Ð°Ð²Ð°Ñ Ð¼Ñ ÑглÑбим ÑÑо понимание дополниÑелÑнÑми пÑимеÑами, а Ñакже ÑаÑÑмоÑÑим, ÑÑо пÑоиÑÑ Ð¾Ð´Ð¸Ñ Ñ Ð¿Ð°Ð¼ÑÑÑÑ.
ÐомменÑаÑии
<code>, Ð´Ð»Ñ Ð½ÐµÑколÑÐºÐ¸Ñ ÑÑÑок кода — Ñег<pre>, еÑли болÑÑе 10 ÑÑÑок — ÑÑÑÐ»ÐºÑ Ð½Ð° пеÑоÑниÑÑ (plnkr, JSBin, codepenâ¦)