Яка область змінних у javascript? Чи мають у них все ті ж області застосування на відміну від зовнішньої функції? Або це навіть має значення? Також де зберігаються змінні, якщо вони визначені глобально?
Яка область змінних у javascript? Чи мають у них все ті ж області застосування на відміну від зовнішньої функції? Або це навіть має значення? Також де зберігаються змінні, якщо вони визначені глобально?
Відповіді:
JavaScript має лексичне (також його називають статичним) визначення і закриття. Це означає, що ви можете вказати область ідентифікатора, переглянувши вихідний код.
Чотири сфери застосування:
Поза окремими випадками глобальної та модульної області, змінні оголошуються за допомогою var
(область функцій), let
(область блоку) та const
(область блоку). Більшість інших форм декларації ідентифікатора мають жорсткий режим блоку.
Область застосування - область кодової бази, над якою діє ідентифікатор.
Лексичне середовище - це відображення між іменами ідентифікаторів та пов'язаними з ними значеннями.
Область застосування складається з пов'язаного гніздування лексичних середовищ, причому кожен рівень вкладеності відповідає лексичному середовищу контексту виконання предків.
Ці пов'язані лексичні середовища утворюють сферу "ланцюга". Розв’язання ідентифікатора - це процес пошуку уздовж цього ланцюга для відповідного ідентифікатора.
Роздільна здатність ідентифікатора відбувається лише в одному напрямку: назовні. Таким чином, зовнішнє лексичне середовище не може "бачити" внутрішнє лексичне середовище.
У вирішенні сфери дії ідентифікатора в JavaScript є три важливі фактори :
Деякі із способів визначити ідентифікатори:
var
, let
іconst
var
в нестрогому режимі)import
заявиeval
Деякі з ідентифікаторів локацій можна оголосити:
Ідентифікатори, оголошені за допомогою, var
мають область функцій , за винятком випадків, коли вони оголошуються безпосередньо в глобальному контексті, і в цьому випадку вони додаються як властивості глобального об'єкта і мають глобальну область застосування. Існують окремі правила їх використання у eval
функціях.
Ідентифікатори, задекларовані за допомогою let
та const
мають блок-сферу , за винятком випадків, коли вони оголошені безпосередньо в глобальному контексті, і в цьому випадку вони мають глобальну сферу застосування.
Примітка: let
, const
і var
все піднімають . Це означає, що їх логічне положення визначення є вершиною сфери їх застосування (блоком або функцією). Однак змінні, оголошені використаними, let
і const
не можуть бути прочитані або призначені доти, поки контроль не передає точку декларації у вихідний код. Проміжний період відомий як часова мертва зона.
function f() {
function g() {
console.log(x)
}
let x = 1
g()
}
f() // 1 because x is hoisted even though declared with `let`!
Назви параметрів функції присвоюються тілу функції. Зауважте, що в цьому є невелика складність. Функції, оголошені як аргументи за замовчуванням, близькі до списку параметрів , а не тіла функції.
Оголошення функцій мають область блоку в суворому режимі, а функціональну область - в не строгому режимі. Примітка: нестрогий режим - це складний набір нових правил, заснованих на химерних історичних реалізаціях різних браузерів.
Визначені вирази функцій визначаються для себе (наприклад, з метою рекурсії).
У нестрогому режимі неявно визначені властивості глобального об'єкта мають глобальну сферу застосування, оскільки глобальний об'єкт розташований у верхній частині ланцюга області. У суворому режимі це заборонено.
У eval
рядках змінні, оголошені за допомогою, var
будуть розміщені в поточному діапазоні або, якщо eval
вони використовуються опосередковано, як властивості глобального об'єкта.
Нижче буде кидати ReferenceError , тому що імена x
, y
і z
не має ніякого значення поза функцією f
.
function f() {
var x = 1
let y = 1
const z = 1
}
console.log(typeof x) // undefined (because var has function scope!)
console.log(typeof y) // undefined (because the body of the function is a block)
console.log(typeof z) // undefined (because the body of the function is a block)
Нижче наведено ReferenceError для y
та z
, але не для x
, оскільки видимість x
не обмежена блоком. Блоки, що визначають тіла керуючих структур, як if
, for
і while
, поводяться аналогічно.
{
var x = 1
let y = 1
const z = 1
}
console.log(x) // 1
console.log(typeof y) // undefined because `y` has block scope
console.log(typeof z) // undefined because `z` has block scope
Далі x
видно зовні циклу, оскільки var
має область функцій:
for(var x = 0; x < 5; ++x) {}
console.log(x) // 5 (note this is outside the loop!)
... через таку поведінку вам потрібно бути обережним щодо закриття змінних, оголошених використанням var
в циклі. Тут x
задекларований лише один екземпляр змінної , і він логічно розташований поза циклом.
Наступні друкуються 5
п'ять разів, а потім 5
шостий раз друкуються для console.log
зовнішньої петлі:
for(var x = 0; x < 5; ++x) {
setTimeout(() => console.log(x)) // closes over the `x` which is logically positioned at the top of the enclosing scope, above the loop
}
console.log(x) // note: visible outside the loop
Наступні відбитки, undefined
оскільки x
це блок-область. Зворотні дзвінки виконуються по черзі асинхронно. Нова поведінка для let
змінних означає , що кожна анонімна функція зімкнулася над іншою змінною з ім'ям x
( в відміну від неї зробили б з var
), і так цілих чисел 0
через 4
роздруковуються.:
for(let x = 0; x < 5; ++x) {
setTimeout(() => console.log(x)) // `let` declarations are re-declared on a per-iteration basis, so the closures capture different variables
}
console.log(typeof x) // undefined
Наведене нижче НЕ кине а, ReferenceError
тому що видимість x
не обмежується блоком; однак вона буде надрукована, undefined
оскільки змінна не була ініціалізована (через if
висловлювання).
if(false) {
var x = 1
}
console.log(x) // here, `x` has been declared, but not initialised
Змінна, оголошена вгорі for
циклу за допомогою let
, прив'язується до тіла циклу:
for(let x = 0; x < 10; ++x) {}
console.log(typeof x) // undefined, because `x` is block-scoped
Наступне буде кидати a, ReferenceError
оскільки видимість x
обмежується блоком:
if(false) {
let x = 1
}
console.log(typeof x) // undefined, because `x` is block-scoped
Змінні, задекларовані за допомогою модулів var
, let
або const
всі вони відносяться до:
// module1.js
var x = 0
export function f() {}
//module2.js
import f from 'module1.js'
console.log(x) // throws ReferenceError
Далі буде оголошено властивість глобального об'єкта, оскільки змінні, оголошені з використанням var
у глобальному контексті, додаються як властивості до глобального об'єкта:
var x = 1
console.log(window.hasOwnProperty('x')) // true
let
і const
в глобальному контексті не додають властивості до глобального об'єкта, але все ж мають глобальний обсяг:
let x = 1
console.log(window.hasOwnProperty('x')) // false
Параметри функції можна вважати оголошеними в тілі функції:
function f(x) {}
console.log(typeof x) // undefined, because `x` is scoped to the function
Параметри блоку лову відносяться до тіла лову блоку:
try {} catch(e) {}
console.log(typeof e) // undefined, because `e` is scoped to the catch block
Ім'яні вирази функцій присвоюються лише самому виразу:
(function foo() { console.log(foo) })()
console.log(typeof foo) // undefined, because `foo` is scoped to its own expression
У не строгому режимі неявно визначені властивості глобального об'єкта мають загальний обсяг. У суворому режимі ви отримуєте помилку.
x = 1 // implicitly defined property on the global object (no "var"!)
console.log(x) // 1
console.log(window.hasOwnProperty('x')) // true
У не строгому режимі декларації функцій мають область функцій. У суворому режимі вони мають блок-сферу.
'use strict'
{
function foo() {}
}
console.log(typeof foo) // undefined, because `foo` is block-scoped
Обсяг визначається як лексична область коду, над якою діє ідентифікатор.
В JavaScript, кожна функція-об'єкт має приховану [[Environment]]
посилання , яка є посиланням на лексичну середу з контексті виконання (кадрі стеки) , в протягом якого він був створений.
Коли ви викликаєте функцію, викликається прихований [[Call]]
метод. Цей метод створює новий контекст виконання та встановлює зв'язок між новим контекстом виконання та лексичним середовищем функції-об'єкта. Це робиться шляхом копіювання [[Environment]]
значення на об'єкт функції у зовнішнє посилання поле на лексичне середовище нового контексту виконання.
Зауважимо, що цей зв’язок між новим контекстом виконання та лексичним середовищем об’єкта функції називається a закриттям .
Таким чином, в JavaScript обсяг реалізується через лексичні середовища, пов'язані разом у "ланцюжку" за допомогою зовнішніх посилань. Цей ланцюжок лексичних середовищ називається ланцюжком дії, і роздільна здатність ідентифікатора відбувається шляхом пошуку ланцюга для відповідного ідентифікатора.
Дізнайтеся більше .
Javascript використовує ланцюги областей для встановлення області для даної функції. Зазвичай існує одна глобальна область, і кожна визначена функція має власну вкладену область. Будь-яка функція, визначена в іншій функції, має локальну область, яка пов'язана із зовнішньою функцією. Завжди позиція у джерелі визначає область застосування.
Елементом ланцюга області є в основному Карта з вказівником на його батьківську область.
При вирішенні змінної javascript запускається в найпотужнішому обсязі і шукає назовні.
Змінні, оголошені в усьому світі, мають глобальну сферу застосування. Змінні, задекларовані в межах функції, відносяться до цієї функції та тіньові глобальні змінні з однойменною назвою.
(Я впевнений, що є багато тонкощів, які справжні програмісти JavaScript зможуть вказати в інших відповідях. Зокрема, я натрапив на цю сторінку про те, що саме this
означає в будь-який час. Сподіваємось, цього ще вступного посилання достатньо, щоб розпочати роботу, хоча .)
Традиційно JavaScript дійсно має лише два типи сфери застосування:
Я не буду деталізувати це, оскільки вже існує багато інших відповідей, що пояснюють різницю.
В останні специфікації JavaScript тепер також дозволяють третій обсяг:
Традиційно ви створюєте такі змінні:
var myVariable = "Some text";
Змінні області блоку створюються так:
let myVariable = "Some text";
Щоб зрозуміти різницю між функціональною сферою та областю блоку, врахуйте наступний код:
// i IS NOT known here
// j IS NOT known here
// k IS known here, but undefined
// l IS NOT known here
function loop(arr) {
// i IS known here, but undefined
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
for( var i = 0; i < arr.length; i++ ) {
// i IS known here, and has a value
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
};
// i IS known here, and has a value
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
for( let j = 0; j < arr.length; j++ ) {
// i IS known here, and has a value
// j IS known here, and has a value
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
};
// i IS known here, and has a value
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
}
loop([1,2,3,4]);
for( var k = 0; k < arr.length; k++ ) {
// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS NOT known here
};
for( let l = 0; l < arr.length; l++ ) {
// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS known here, and has a value
};
loop([1,2,3,4]);
// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS NOT known here
Тут ми можемо побачити, що наша змінна j
відома лише в першому для циклу, але не до і після. І все ж наша змінна i
відома у всій функції.
Крім того, врахуйте, що змінні в масштабі блоку не відомі до їх оголошення, оскільки вони не піднімаються. Вам також не дозволяється повторно декларувати одну і ту ж змінну, що охоплюється в межах одного блоку. Це робить змінні, що охоплюють блок, менше схильних до помилок, ніж глобальні або функціонально обмежені змінні, які піднімаються і які не створюють помилок у випадку численних оголошень.
Наскільки це безпечно використовувати сьогодні чи ні, залежить від вашого оточення:
Якщо ви пишете код JavaScript на стороні сервера ( Node.js ), можете сміливо використовувати let
оператор.
Якщо ви пишете код на JavaScript на стороні клієнта і використовуєте транспілер на базі браузера (наприклад, Traceur або автономна версія ), ви можете сміливо використовувати let
виписку, однак ваш код, швидше за все, буде оптимальним щодо продуктивності.
Якщо ви пишете JavaScript-код на стороні клієнта та використовуєте транслятор на основі вузла (наприклад, скрипт оболонки прослідковування або Babel ), ви можете сміливо використовувати let
оператор. Оскільки ваш браузер знатиме лише про перекладений код, недоліки в роботі повинні бути обмеженими.
Якщо ви пишете код JavaScript на стороні клієнта і не використовуєте транспілятор, вам потрібно врахувати підтримку браузера.
Ось такі браузери, які взагалі не підтримують let
:
Щоб переглянути оновлений огляд того, який браузер підтримує let
заяву під час прочитання цієї відповіді, дивіться цю Can I Use
сторінку .
(*) Змінні на глобальному та функціональному рівні можуть бути ініціалізовані та використані до їх оголошення, оскільки змінні JavaScript підняті . Це означає, що декларації завжди знаходяться на вершині сфери застосування.
Ось приклад:
<script>
var globalVariable = 7; //==window.globalVariable
function aGlobal( param ) { //==window.aGlobal();
//param is only accessible in this function
var scopedToFunction = {
//can't be accessed outside of this function
nested : 3 //accessible by: scopedToFunction.nested
};
anotherGlobal = {
//global because there's no `var`
};
}
</script>
Ви хочете розглянути питання про закриття та використання їх для створення приватних членів .
Як я розумію, ключовим є те, що у Javascript є визначення рівня функціональних показників порівняно з більш поширеним складовим блоком С.
У "Javascript 1.7" (розширення Mozilla до Javascript) можна також оголосити змінні блоку області із let
заявою :
var a = 4;
let (a = 3) {
alert(a); // 3
}
alert(a); // 4
let
.
Ідея розбору в JavaScript, коли оригінально розроблений Брендан Ейх, виникла з сценарію мови HyperCard HyperTalk .
Цією мовою дисплеї були зроблені аналогічно стеку індексних карт. Була основна картка, яку називали тлом. Він був прозорим і його можна розглядати як нижню карту. Будь-який вміст на цій базовій карті ділиться картками, розміщеними на ній. Кожна карта, розміщена зверху, мала свій власний вміст, який брав перевагу над попередньою картою, але все ж мав доступ до попередніх карток, якщо бажано.
Саме так розроблена система скопірування JavaScript. Він просто має різні назви. Картки в JavaScript відомі як виконавчі контексти ECMA . Кожен з цих контекстів містить три основні частини. Змінне середовище, лексичне середовище та пов'язане це. Повертаючись до посилання на картки, лексичне середовище містить увесь вміст попередніх карток нижче в стеку. Поточний контекст знаходиться у верхній частині стека, і будь-який вміст, оголошений там, буде зберігатися у змінному середовищі. Змінне середовище матиме перевагу у випадку зіткнення імен.
Це прив'язка вказуватиме на об'єкт, що містить. Іноді сфери дії або контексти виконання змінюються без зміни об'єкта, що міститься, наприклад, у оголошеній функції, де може міститися об'єкт, window
або функція конструктора.
Ці контексти виконання створюються в будь-який час передачі контролю. Контроль передається, коли код починає виконуватись, і це в першу чергу здійснюється від виконання функції.
Так це технічне пояснення. На практиці важливо пам’ятати про це в JavaScript
Застосовуючи це до одного з попередніх прикладів (5. "Закриття") на цій сторінці, можна прослідкувати за стеком контексту виконання. У цьому прикладі в стеці є три контексти. Вони визначаються зовнішнім контекстом, контекстом у функції, що викликається негайно, викликаною var Six, і контекстом у поверненій функції всередині функції var Six, яка негайно викликається.
i ) Зовнішній контекст. Він має змінне середовище a = 1
ii ) Контекст IIFE, він має лексичне середовище a = 1, але змінне середовище a = 6, яке має перевагу в стеку
iii ) Контекст функцій, що повертається, має лексичний характер оточення a = 6, і це значення, на яке посилається сповіщення при виклику.
1) Існує глобальна сфера дії, сфера функціонування, а також сфера використання та вилов. Загалом для області змінної немає області "блок" рівня "блоку" - оператори з і вилов додають імена до своїх блоків.
2) Області застосування вкладені функціями аж до глобальної сфери.
3) Властивості вирішуються шляхом проходження прототипу. Оператор with приносить назви властивостей об'єкта в лексичну область, визначену блоком.
EDIT: ECMAAScript 6 (Гармонія) призначений для підтримки нехай, і я знаю, що хром дозволяє прапор "гармонії", тому, можливо, він підтримує його.
Нехай це буде підтримка для визначення рівня блоків, але ви повинні використовувати ключове слово, щоб зробити це.
EDIT: Грунтуючись на вказівці Бенджаміна на коментарі з приводу та вилову у коментарях, я відредагував публікацію та додав більше. І оператори с, і вилов вводять змінні у відповідні блоки, і це блокова область. Ці змінні псевдоніми властивостям об'єктів, що передаються їм.
//chrome (v8)
var a = { 'test1':'test1val' }
test1 // error not defined
with (a) { var test1 = 'replaced' }
test1 // undefined
a // a.test1 = 'replaced'
EDIT: Уточнюючий приклад:
test1 присвоюється блоку з блоком, але має псевдонім до a.test1. 'Var test1' створює нову змінну test1 у верхньому лексичному контексті (функціональній чи глобальній), якщо тільки вона не є властивістю a - якою вона є.
Yikes! Будьте обережні, використовуючи "з" - подібно до того, як var - noop, якщо змінна вже визначена у функції, вона також є noop стосовно ім'я, імпортованого з об'єкта! Трохи підкреслити назву, яка вже визначена, зробить це набагато безпечнішим. Я особисто ніколи не буду користуватися через це.
with
оператор - це форма визначення рівня блоку, але catch
пропозиції є набагато більш поширеною формою (Fun Fun, v8 реалізується catch
з a with
) - це майже єдині форми блокового обстеження в самому JavaScript (Тобто функція, глобальна, спробуйте / ловити , з та їх похідними), проте хост-середовища мають різні поняття про масштабування - наприклад, вбудовані події в браузері та vm-модулі NodeJS.
Я виявив, що багато людей, які не знають JavaScript, мають проблеми з розумінням того, що успадкування доступне за мовою за замовчуванням, і ця сфера функціонування поки є єдиною сферою застосування. Я надав розширення до краси, про яке писав наприкінці минулого року під назвою JSPretty. Кольори функції функціонують в коді і завжди пов'язують колір з усіма змінними, заявленими в цій області. Замикання наочно демонструється, коли змінна з кольором з однієї області використовується в іншій області.
Спробуйте цю функцію за адресою:
Дивіться демонстрацію на веб-сайті:
Переглянути код за адресою:
В даний час функція пропонує підтримку глибини 16 вкладених функцій, але в даний час не забарвлює глобальні змінні.
Діапазон JavaScript має лише два типи:
var
ключовим словом, має функціональну область.Щоразу, коли викликається функція, створюється об'єкт змінної області (і включається в ланцюг області), за яким слідують змінні в JavaScript.
a = "global";
function outer(){
b = "local";
console.log(a+b); //"globallocal"
}
outer();
Область застосування ->
a
і outer
функції знаходяться на найвищому рівні в ланцюзі області.variable scope object
(і включається в ланцюг сфери застосування), що додається зі змінною b
всередині неї.Тепер, коли потрібна змінна, a
вона спочатку шукає найближчу область змінної області, а якщо змінної немає, ніж вона переходить до наступного об'єкта ланцюга змінної області дії. Що в цьому випадку - рівень вікна.
Просто для додання інших відповідей, область - це перегляд списку всіх оголошених ідентифікаторів (змінних) і застосовує суворий набір правил щодо того, як вони доступні для виконуваного в даний час коду. Цей огляд може бути призначений для присвоєння змінній, яка є посиланням на LHS (на лівій стороні), або може бути в цілях отримання його значення, яке є посиланням RHS (праворуч). Ці пошуки - це те, що працює двигун JavaScript всередині, коли він збирає та виконує код.
Отже, з цієї точки зору, я думаю, що картина допомогла б мені знайти книгу про сфери та закриття Кайла Сімпсона:
Цитуючи його електронну книгу:
Будівля представляє вкладений набір правил нашої програми. Перший поверх будівлі представляє ваші сфери виконання, де б ви не знаходилися. Верхній рівень будівлі - це глобальна сфера. Ви вирішуєте посилання на LHS та RHS, дивлячись на свій поточний поверх, а якщо не знайдете, піднявши ліфт на наступний поверх, заглянувши туди, то на наступний тощо. Як тільки ви дістанетесь до останнього поверху (глобальна сфера), ви або знайдете те, що шукаєте, або не зробите. Але ви повинні зупинитись незалежно.
Варто зазначити одне, що варто відзначити: "Перегляд області припиняється, коли він знайде першу відповідність".
Ця ідея "рівнів області" пояснює, чому "це" можна змінити за допомогою новоствореної області, якщо вона шукається у вкладеній функції. Ось посилання, яке містить усі ці деталі, все, що ви хотіли знати про область JavaScript
запустити код. сподіваємось, що це дасть уявлення про масштаби
Name = 'global data';
document.Name = 'current document data';
(function(window,document){
var Name = 'local data';
var myObj = {
Name: 'object data',
f: function(){
alert(this.Name);
}
};
myObj.newFun = function(){
alert(this.Name);
}
function testFun(){
alert("Window Scope : " + window.Name +
"\nLocal Scope : " + Name +
"\nObject Scope : " + this.Name +
"\nCurrent document Scope : " + document.Name
);
}
testFun.call(myObj);
})(window,document);
Глобальні змінні точно схожі на світові зірки (Джекі Чан, Нельсон Мандела). Ви можете отримати доступ до них (отримати або встановити значення) з будь-якої частини програми. Глобальні функції схожі на глобальні події (Новий рік, Різдво). Ви можете їх виконати (зателефонувати) з будь-якої частини вашої програми.
//global variable
var a = 2;
//global function
function b(){
console.log(a); //access global variable
}
Якщо ви перебуваєте в США, ви, можливо, знаєте Кім Кардашян, сумно відому знаменитість (їй якось вдається скласти таблоїди). Але люди за межами США її не впізнають. Вона - місцева зірка, прив’язана до своєї території.
Локальні змінні схожі на місцеві зірки. Ви можете отримати доступ до них (отримати або встановити значення) лише в межах області. Локальна функція подібна до локальних подій - ви можете виконувати лише (святкувати) всередині цього діапазону. Якщо ви хочете отримати доступ до них за межами області, ви отримаєте помилку посилання
function b(){
var d = 21; //local variable
console.log(d);
function dog(){ console.log(a); }
dog(); //execute local function
}
console.log(d); //ReferenceError: dddddd is not defined
Перевірте цю статтю, щоб глибше зрозуміти сферу застосування
Є лише два типи областей JavaScript:
Отже, будь-які блоки, крім функцій, не створюють нової області. Це пояснює, чому for-loops перезаписують зовнішні змінні області:
var i = 10, v = 10;
for (var i = 0; i < 5; i++) { var v = 5; }
console.log(i, v);
// output 5 5
Використання функцій:
var i = 10, v = 10;
$.each([0, 1, 2, 3, 4], function(i) { var v = 5; });
console.log(i,v);
// output 10 10
У першому прикладі не було блокової області, тому спочатку оголошені змінні були перезаписані. У другому прикладі з'явилася нова область застосування завдяки функції, тому спочатку оголошені змінні були ЗАМЕНЕНІ, а не перезаписані.
Це майже все, що вам потрібно знати в частині розміщення JavaScript, за винятком:
Таким чином, ви можете бачити, що масштабування JavaScript насправді надзвичайно просте, хоч і не завжди інтуїтивно зрозуміле. Деякі речі, про які слід пам’ятати:
Отже цей код:
var i = 1;
function abc() {
i = 2;
var i = 3;
}
console.log(i); // outputs 1
еквівалентно:
var i = 1;
function abc() {
var i; // var declaration moved to the top of the scope
i = 2;
i = 3; // the assignment stays where it is
}
console.log(i);
Це може здатися протилежним інтуїтивно зрозумілим, але це має сенс з точки зору імперативного дизайнера мови.
const
' і ' let
'Ви повинні використовувати блок-аналіз для кожної створеної змінної, як і більшість інших основних мов. var
є застарілим . Це робить ваш код більш безпечним та ретельним.
const
слід використовувати в 95% випадків . Це робить його таким чином, що посилання на змінну не може змінитися. Властивості масиву, об'єкта та DOM можуть змінюватися і, швидше за все, бути const
.
let
слід використовувати для будь-якої змінної, яка очікує перепризначення. Це включає в себе цикл for. Якщо ви коли-небудь змінюєте значення після ініціалізації, використовуйте let
.
Область блоку означає, що змінна буде доступна лише в дужках, в яких вона оголошена. Це поширюється на внутрішні сфери, включаючи анонімні функції, створені у межах вашої сфери.
Спробуйте цей цікавий приклад. У наведеному нижче прикладі, якщо число було ініціалізовано на 0, ви побачите 0, а потім 1. За винятком a - це об'єкт, і javascript передасть f1 вказівник, а не його копію. У результаті ви отримуєте одне і те ж попередження обох разів.
var a = new Date();
function f1(b)
{
b.setDate(b.getDate()+1);
alert(b.getDate());
}
f1(a);
alert(a.getDate());
У JS є лише сфери функціонування. Не блокуйте сфери застосування! Ви також можете бачити те, що піднімається.
var global_variable = "global_variable";
var hoisting_variable = "global_hoist";
// Global variables printed
console.log("global_scope: - global_variable: " + global_variable);
console.log("global_scope: - hoisting_variable: " + hoisting_variable);
if (true) {
// The variable block will be global, on true condition.
var block = "block";
}
console.log("global_scope: - block: " + block);
function local_function() {
var local_variable = "local_variable";
console.log("local_scope: - local_variable: " + local_variable);
console.log("local_scope: - global_variable: " + global_variable);
console.log("local_scope: - block: " + block);
// The hoisting_variable is undefined at the moment.
console.log("local_scope: - hoisting_variable: " + hoisting_variable);
var hoisting_variable = "local_hoist";
// The hoisting_variable is now set as a local one.
console.log("local_scope: - hoisting_variable: " + hoisting_variable);
}
local_function();
// No variable in a separate function is visible into the global scope.
console.log("global_scope: - local_variable: " + local_variable);
Я розумію, що існує 3 сфери: глобальна сфера дії, доступна в усьому світі; локальна область, доступна для всієї функції незалежно від блоків; і область блоку, доступна лише для блоку, висловлювання або виразу, для якого воно було використано. Глобальна та локальна сфера дії вказуються на ключове слово 'var', або в межах функції, або поза її межами, а область блоку вказується на ключове слово 'let'.
Тим, хто вважає, що існує лише глобальний та локальний обсяг, будь ласка, поясніть, чому Mozilla матиме цілу сторінку, що описує нюанси області блоку в JS.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
Дуже поширена проблема, ще не описана тим, що часто зустрічаються фронтальні кодери - це область, видима для обробника подій вбудованого тексту в HTML - наприклад, з
<button onclick="foo()"></button>
Обсяг змінних, на on*
які може посилатися атрибут, повинен бути:
querySelector
як окрема змінна вкаже на document.querySelector
; рідко)В іншому випадку ви отримаєте ReferenceError, коли викликається обробник. Так, наприклад, якщо обробник вбудованого посилання посилається на функцію, яка визначена всередині, window.onload
або $(function() {
посилання вийде з ладу, тому що вбудований обробник може посилатися лише на змінні в глобальній області, а функція не є глобальною:
Властивості document
та властивості елемента, до якого додається обробник, також можуть посилатися як окремі змінні всередині вбудованих обробників, оскільки вбудовані обробники викликаються всередині двох with
блоків , одного для document
елемента, одного для елемента. Ланцюг застосування змінних всередині цих обробників є надзвичайно неінтуїтивним , і обробник робочих подій, ймовірно, потребує функції, яка має бути глобальною (а також слід уникати зайвого глобального забруднення ).
Оскільки ланцюг сфери дії всередині вбудованих обробників настільки дивний , а оскільки вбудовані обробники вимагають глобального забруднення для роботи, а оскільки вбудовані обробники іноді вимагають уникнути потворних рядків при передачі аргументів, їх, мабуть, простіше уникнути. Натомість, прикріплюйте обробники подій за допомогою Javascript (наприклад, з addEventListener
), а не з розміткою HTML.
З іншого боку, на відміну від звичайних <script>
тегів, які працюють на найвищому рівні, код всередині модулів ES6 працює у власному приватному масштабі. Змінна, визначена у верхній частині звичайного <script>
тегу, є глобальною, тому ви можете посилатися на неї в інших <script>
тегах, таких як:
Але верхній рівень модуля ES6 не є глобальним. Змінна, оголошена у верхній частині модуля ES6, буде видима лише всередині цього модуля, крім випадків, коли змінна явно export
редагується, або якщо вона не присвоєна властивості глобального об'єкта.
Верхній рівень модуля ES6 аналогічний рівню внутрішньої частини IIFE на верхньому рівні в нормі <script>
. Модуль може посилатися на будь-які змінні, які є глобальними, і нічого не може посилатися ні на що всередині модуля, якщо модуль явно не призначений для цього.
У JavaScript є два типи сфери застосування:
Функція "Далі" має змінну локальної області carName
. І ця змінна недоступна за межами функції.
function myFunction() {
var carName = "Volvo";
alert(carName);
// code here can use carName
}
Клас "Нижній" має змінну глобальної області застосування carName
. І ця змінна доступна звідусіль у класі.
class {
var carName = " Volvo";
// code here can use carName
function myFunction() {
alert(carName);
// code here can use carName
}
}
ES5
і раніше:Змінні в Javascript спочатку (попередньо ES6
) лексично функціонували. Термін, що визначається лексично, означає, що ви можете побачити область змінних, "переглянувши" код.
Кожна змінна, оголошена var
ключовим словом, привласнюється до функції. Однак якщо в цій функції оголошено інші функції, ці функції матимуть доступ до змінних зовнішніх функцій. Це називається ланцюгом сфери застосування . Це працює наступним чином:
// global scope
var foo = 'global';
var bar = 'global';
var foobar = 'global';
function outerFunc () {
// outerFunc scope
var foo = 'outerFunc';
var foobar = 'outerFunc';
innerFunc();
function innerFunc(){
// innerFunc scope
var foo = 'innerFunc';
console.log(foo);
console.log(bar);
console.log(foobar);
}
}
outerFunc();
Що відбувається , коли ми намагаємося увійти змінні foo
, bar
і foobar
в консолі наступне:
innerFunc
. Тому значення foo вирішено на рядок innerFunc
.innerFunc
. Тому нам потрібно піднятися по ланцюгу розмаху . Спочатку ми розглянемо зовнішню функцію, в якій innerFunc
була визначена функція . Це функція outerFunc
. В області outerFunc
ми можемо знайти смугу змінної, яка містить рядок 'externalFunc'.ES6
(ES 2015) та старші:Ті самі поняття лексично сфери та сфери застосування все ще застосовуються в ES6
. Однак були введені нові способи декларування змінних. Є такі:
let
: створює блок-зміннуconst
: створює змінну в масштабі блоку, яку необхідно ініціалізувати і не може бути переназначенаНайбільша відмінність між var
та let
/ const
є в тому, що var
це функція, в той час як let
/ const
є блоком. Ось приклад для ілюстрації цього:
let letVar = 'global';
var varVar = 'global';
function foo () {
if (true) {
// this variable declared with let is scoped to the if block, block scoped
let letVar = 5;
// this variable declared with let is scoped to the function block, function scoped
var varVar = 10;
}
console.log(letVar);
console.log(varVar);
}
foo();
У наведеному вище прикладі letVar записує значення global, тому що змінні, оголошені з, let
є блок-шкалою. Вони перестають існувати за межами відповідного блоку, тому змінна не може бути доступна поза блоком if.
У EcmaScript5 в основному є дві сфери, локальна сфера та глобальна сфера, але в EcmaScript6 ми маємо в основному три сфери, локальну область, глобальну область застосування та нову область, що називається блок-область .
Приклад області блоку:
for ( let i = 0; i < 10; i++)
{
statement1...
statement2...// inside this scope we can access the value of i, if we want to access the value of i outside for loop it will give undefined.
}
ECMAScript 6 представив ключові слова let and const. Ці ключові слова можна використовувати замість ключового слова var. На відміну від ключового слова var, ключові слова let та const підтримують декларацію локальної області дії в операторах блоку.
var x = 10
let y = 10
const z = 10
{
x = 20
let y = 20
const z = 20
{
x = 30
// x is in the global scope because of the 'var' keyword
let y = 30
// y is in the local scope because of the 'let' keyword
const z = 30
// z is in the local scope because of the 'const' keyword
console.log(x) // 30
console.log(y) // 30
console.log(z) // 30
}
console.log(x) // 30
console.log(y) // 20
console.log(z) // 20
}
console.log(x) // 30
console.log(y) // 10
console.log(z) // 10
Мені дуже подобається прийнята відповідь, але я хочу додати це:
Область застосування збирає та підтримує перегляд усіх оголошених ідентифікаторів (змінних) та застосовує суворий набір правил щодо того, яким чином вони доступні для виконуваного в даний час коду.
Область застосування - це набір правил пошуку змінних за назвою їх ідентифікатора.
У JavaScript існує два типи областей.
Глобальний діапазон : змінна, яка оголошена в глобальному масштабі, може бути використана в будь-якому місці програми дуже гладко. Наприклад:
var carName = " BMW";
// code here can use carName
function myFunction() {
// code here can use carName
}
Функціональна область або Локальна область : змінна, оголошена в цій області, може використовуватися лише в її власній функції. Наприклад:
// code here can not use carName
function myFunction() {
var carName = "BMW";
// code here can use carName
}