Що таке лексичний обсяг?


682

Що таке короткий вступ до лексичного обстеження?


89
У подкасті 58 Джоел заохочує подібні питання, оскільки він хоче, щоб ТАК став місцем відповідей, навіть якщо на них відповіли в інших місцях. Це справедливе питання, хоча можна було б поставити його трохи ввічливіше.
Ральф М. Рікенбах

5
@rahul Я розумію, це старе питання. Але я впевнений, що навіть у 2009 році SO очікував, що запитуючі докладуть деяких основних зусиль для її вирішення. Оскільки це коштує не показує жодних - або зусиль на всіх. Можливо, саме тому багато хто зголосився?
ПП

13
Можливо, запитуючий не володіє (або не володіє англійською мовою) під час написання цього запитання
Мартін

27
Питання ввічливе, він просто каже, що хоче. Ви вільні відповідати. Тут немає потреби в надмірній політичності.
Markus Siebeneicher

25
Я думаю, що подібні питання є чудовими, оскільки вони створюють вміст для ТА. IMO, який хвилює, якщо на запитання не буде зусиль ... відповіді матимуть великий вміст, і це важливо на цій дошці повідомлень.
Jwan622

Відповіді:


686

Я розумію їх на прикладах. :)

По-перше, лексична сфера (також її називають статичною сферою ) у C-подібному синтаксисі:

void fun()
{
    int x = 5;

    void fun2()
    {
        printf("%d", x);
    }
}

Кожен внутрішній рівень може отримати доступ до своїх зовнішніх рівнів.

Існує ще один спосіб, який називається динамічним діапазоном, використовуваним першою реалізацією Lisp , знову в C-подібному синтаксисі:

void fun()
{
    printf("%d", x);
}

void dummy1()
{
    int x = 5;

    fun();
}

void dummy2()
{
    int x = 10;

    fun();
}

Тут funможна або отримати доступ xдо dummy1або dummy2, або будь-яку xв будь-яку функцію, яка дзвонить funіз xзаявленим в ній.

dummy1();

буде надруковано 5,

dummy2();

надрукує 10.

Перший називається статичним, оскільки його можна вивести під час компіляції, а другий - динамічним, оскільки зовнішня область є динамічною і залежить від ланцюгового виклику функцій.

Я вважаю, що статичне обстеження легше для ока. Більшість мов зрештою пішли цим шляхом, навіть Лісп (можна зробити обидві, правда?). Динамічне масштабування - це як передача посилань усіх змінних на викликану функцію.

Як приклад того, чому компілятор не може вивести зовнішню динамічну сферу функції, розглянемо наш останній приклад. Якщо ми пишемо щось подібне:

if(/* some condition */)
    dummy1();
else
    dummy2();

Ланцюг виклику залежить від стану часу виконання. Якщо це правда, то ланцюжок викликів виглядає так:

dummy1 --> fun()

Якщо умова помилкова:

dummy2 --> fun()

Зовнішня сфера застосування funв обох випадках викликає дзвінок плюс дзвінок, що телефонує, і так далі .

Зазначимо лише, що мова С не дозволяє вкладених функцій, ні динамічного масштабування.


19
Я також хотів би зазначити дуже простий для розуміння підручник, який я щойно знайшов. Приклад Арака є приємним, але може бути занадто коротким для того, хто потребує більше прикладів (насправді, порівняння з іншими мовами ..). Поглянь. Важливо , щоб зрозуміти це , оскільки це ключове слово призведе нас до розуміння лексичної області. howtonode.org/what-is-this
CppLearner

9
Це хороша відповідь. Але питання позначене тегом JavaScript. Тому я вважаю, що це не слід позначати як прийняту відповідь. Лексична сфера конкретно в JS відрізняється
Боянг

6
Надзвичайно хороша відповідь. Дякую. @Boyang Я не згоден. Я не кодер Lisp, але знайшов приклад Lisp корисним, оскільки це приклад динамічного масштабування, якого ви не отримуєте в JS.
dudewad

4
Спочатку я вважав, що приклад є дійсним кодом C, і я був плутаний, чи є динамічне оцінювання в C. Можливо, відмова від відповідальності в кінці може бути зміщена до прикладу коду?
Yangshun Tay

2
Це все ще дуже корисна відповідь, але я вважаю, що @Boyang правильна. Ця відповідь посилається на "рівень", який більше відповідає лінії області блоку, яку має C. За замовчуванням JavaScript не має області блоку, тому forтипова проблема всередині циклу. Лексична область для JavaScript тільки на функціональному рівні , якщо тільки ES6 letабо constвикористовується.
icc97

275

Давайте спробуємо якомога коротше визначення:

Лексичне оцінювання визначає, як імена змінних розв’язуються в вкладених функціях: внутрішні функції містять область батьківських функцій, навіть якщо батьківська функція повернулася .

Це все, що там є!


21
Остання частина: "навіть якщо батьківська функція повернулася" називається закриттям.
Хуанма Менендес

1
Розуміння лексичного обліку та закриття лише в одному сенсі. Дякую!!
Підземелля

63
var scope = "I am global";
function whatismyscope(){
   var scope = "I am just a local";
   function func() {return scope;}
   return func;
}

whatismyscope()()

Наведений вище код поверне "Я просто місцевий". Це не повернеться "Я глобальний". Оскільки функція func () підраховує те, де спочатку було визначено, що знаходиться в межах функції Whatismyscope.

Це не буде турбувати те, що його називають (загальний масштаб / навіть в межах іншої функції), тому значення глобального масштабу I I global не друкується.

Це називається лексичним обстеженням, де " функції виконуються за допомогою ланцюга діапазону, який діяв, коли вони були визначені " - відповідно до Посібника з визначення JavaScript.

Лексичний обсяг - це дуже дуже потужне поняття.

Сподіваюся, це допомагає .. :)


3
це дуже приємне пояснення, я хочу додати ще одну річ, якщо ви пишете функцію func () {return this.scope;}, тоді вона повернеться "Я глобальний", просто використовуйте це ключове слово, і ваш обсяг отримає зміни
Rajesh Kumar Bhawsar

41

Лексичний (AKA статичний) масштаб відноситься до визначення сфери застосування змінної виходячи виключно з її положення в текстовому корпусі коду. Змінна завжди посилається на її середовище верхнього рівня. Це добре зрозуміти стосовно динамічної сфери.


41

Область застосування визначає область, де доступні функції, змінні тощо. Наприклад, доступність змінної визначається в її контексті, скажімо, функція, файл або об'єкт, вони визначені в. Ми зазвичай називаємо ці локальні змінні.

Лексична частина означає, що ви можете отримати сферу застосування, прочитавши вихідний код.

Лексичний обсяг також відомий як статичний обсяг.

Динамічний діапазон визначає глобальні змінні, які можна викликати або посилати з будь-якого місця після їх визначення. Іноді їх називають глобальними змінними, навіть незважаючи на те, що глобальні змінні в більшості програмних мов мають лексичну сферу. Це означає, що зчитування коду може бути отримано, що змінна є доступною в цьому контексті. Можливо, потрібно знайти довідку про використання або включення, щоб знайти встановлення або визначення, але код / ​​компілятор знає про змінну в цьому місці.

У динамічному масштабуванні, навпаки, ви спочатку шукаєте локальну функцію, потім шукаєте функцію, яка викликала локальну функцію, потім шукаєте в тій функції, яка викликала цю функцію тощо, вгору до стеку викликів. "Динамічний" означає зміну, оскільки стек виклику може бути різним щоразу, коли викликається певна функція, і тому функція може вражати різні змінні залежно від того, звідки вона викликана. (див. тут )

Щоб побачити цікавий приклад для динамічної області, дивіться тут .

Детальніше дивіться тут і тут .

Деякі приклади в Delphi / Object Pascal

Delphi має лексичну сферу застосування.

unit Main;
uses aUnit;  // makes available all variables in interface section of aUnit

interface

  var aGlobal: string; // global in the scope of all units that use Main;
  type 
    TmyClass = class
      strict private aPrivateVar: Integer; // only known by objects of this class type
                                    // lexical: within class definition, 
                                    // reserved word private   
      public aPublicVar: double;    // known to everyboday that has access to a 
                                    // object of this class type
    end;

implementation

  var aLocalGlobal: string; // known to all functions following 
                            // the definition in this unit    

end.

Найближчий Delphi до динамічної сфери - пара функцій RegisterClass () / GetClass (). Про його використання дивіться тут .

Скажімо, час виклику RegisterClass ([TmyClass]) для реєстрації певного класу неможливо передбачити, прочитавши код (він викликається методом натискання кнопки, який називається користувачем), і отримає код GetClass ('TmyClass'). результат чи ні. Виклик до RegisterClass () не повинен бути в лексичній області блоку за допомогою GetClass ();

Іншою можливістю для динамічної області застосування є анонімні методи (закриття) у Delphi 2009, оскільки вони знають змінні своєї функції виклику. Він не слідує шляху виклику звідти рекурсивно і тому не є повністю динамічним.


2
Насправді приватний доступний у цілому підрозділі, де визначено клас. Ось чому "Строгий приватний" був представлений у D2006 році.
Marco van de Voort

2
+1 для простої мови (на відміну від складної мови та прикладів без особливого опису)
Pops

36

Я люблю повнофункціональні мовно-агностичні відповіді людей, як-то @Arak. Оскільки це питання позначене тегом JavaScript , я хотів би чіпнути деякі нотатки, дуже характерні для цієї мови.

У JavaScript нами вибір:

  • як є (немає коригування області)
  • лексичні var _this = this; function callback(){ console.log(_this); }
  • пов'язаний callback.bind(this)

Варто зазначити, я думаю, що JavaScript насправді не має динамічного масштабування . .bindкоригує thisключове слово, і це близько, але технічно не те саме.

Ось приклад, що демонструє обидва підходи. Ви робите це кожен раз, коли приймаєте рішення про те, як розгорнути зворотні дзвінки, щоб це стосувалося обіцянок, обробників подій тощо.

Лексичні

Ось, що можна назвати Lexical Scopingзворотними дзвінками в JavaScript:

var downloadManager = {
  initialize: function() {
    var _this = this; // Set up `_this` for lexical access
    $('.downloadLink').on('click', function () {
      _this.startDownload();
    });
  },
  startDownload: function(){
    this.thinking = true;
    // Request the file from the server and bind more callbacks for when it returns success or failure
  }
  //...
};

Зв'язаний

Ще одним способом розширення є використання Function.prototype.bind:

var downloadManager = {
  initialize: function() {
    $('.downloadLink').on('click', function () {
      this.startDownload();
    }.bind(this)); // Create a function object bound to `this`
  }
//...

Ці методи, наскільки я знаю, поведінково рівнозначні.


Використання bindне впливає на область застосування.
Бен Астон

12

Лексичне оцінювання: Змінні, оголошені поза функцією, є глобальними змінними і їх можна побачити скрізь у програмі JavaScript. Змінні, задекларовані всередині функції, мають функціональну область і видно лише коду, який з’являється всередині цієї функції.


12

IBM визначає це як:

Частина програми або сегментної одиниці, до якої застосовується декларація. Ідентифікатор, оголошений у рутині, відомий у межах цієї програми та у всіх вкладених процедурах. Якщо вкладена рутина оголошує елемент з тим самим іменем, зовнішній елемент недоступний у вкладеній програмі.

Приклад 1:

function x() {
    /*
    Variable 'a' is only available to function 'x' and function 'y'.
    In other words the area defined by 'x' is the lexical scope of
    variable 'a'
    */
    var a = "I am a";

    function y() {
        console.log( a )
    }
    y();

}
// outputs 'I am a'
x();

Приклад 2:

function x() {

    var a = "I am a";

    function y() {
         /*
         If a nested routine declares an item with the same name,
         the outer item is not available in the nested routine.
         */
        var a = 'I am inner a';
        console.log( a )
    }
    y();

}
// outputs 'I am inner a'
x();

8

Лексична сфера означає, що у вкладеній групі функцій внутрішні функції мають доступ до змінних та інших ресурсів їх батьківського обсягу . Це означає, що функції дитини лексично пов'язані з контекстом виконання їхніх батьків. Лексичний обсяг іноді також називають статичним .

function grandfather() {
    var name = 'Hammad';
    // 'likes' is not accessible here
    function parent() {
        // 'name' is accessible here
        // 'likes' is not accessible here
        function child() {
            // Innermost level of the scope chain
            // 'name' is also accessible here
            var likes = 'Coding';
        }
    }
}

Що ви помітите про лексичну область - це те, що воно працює вперед, тобто ім'я може бути доступне контекстами виконання його дітьми. Але це не працює назад до батьків, це означає, що батьки likesне можуть отримати доступ до змінної .

Це також говорить нам, що змінні, що мають однакове ім'я в різних контекстах виконання, отримують перевагу зверху внизу стеку виконання. Змінна, що має ім’я, подібне до іншої змінної, у найпотаємнішій функції (найвищий контекст стеку виконання) матиме вищий пріоритет.

Зауважте, що це взято звідси .


8

Простою мовою, лексична область - це змінна, визначена за межами вашої області, або верхня область автоматично доступна всередині вашої області, а це означає, що вам не потрібно вводити її туди.

Приклад:

let str="JavaScript";

const myFun = () => {
    console.log(str);
}

myFun();

// Вихід: JavaScript


2
Найкоротша і найкраща відповідь для мене на прикладі. Можна було б додати, що функції стрілок ES6 вирішують проблему bind. З ними bindбільше не потрібно. Для отримання додаткової інформації про цю перевірку зміни stackoverflow.com/a/34361380/11127383
Daniel Danielecki

4

Існує важлива частина розмови, що стосується лексичного та динамічного масштабування , якого немає: чітке пояснення тривалості масштабованої змінної - або коли можна отримати доступ до змінної.

Динамічне масштабування лише дуже вільно відповідає "глобальному" масштабуванню в тому, як ми традиційно думаємо про це (причина, за якою я привожу порівняння між ними, - це те, що вже згадувалося - і мені особливо не подобається пов'язане пояснення статті ); це, мабуть, найкраще, ми не робимо порівняння між глобальним та динамічним, хоча, згідно з прив’язаною статтею, нібито, "... [це] корисно як заміна глобально змінених змінних".

Отже, простою англійською мовою, яка важлива відмінність між двома механізмами оцінювання?

Лексичний обсяг був визначений дуже добре у відповідях, наведених вище: змінні, розміщені в межах лексичної точки зору, доступні - або доступні - на локальному рівні функції, в якій вона була визначена.

Однак - оскільки це не фокус ОП - динамічне оцінювання не приділяло великої уваги, а привернутої увазі означає, що йому, мабуть, потрібно трохи більше (це не критика інших відповідей, а скоріше "о, що відповідь, яку ми хотіли б, щоб було трохи більше "). Отже, ось ще трохи:

Динамічне масштабування означає, що змінна є доступною для більшої програми протягом життя виклику функції - або під час виконання функції. Дійсно, Вікіпедія насправді справляється з приємною роботою з поясненням різниці між ними. Щоб не придумати це, ось текст, який описує динамічне масштабування:

... [I] n динамічного масштабування (або динамічного діапазону), якщо сфера імені змінної є певною функцією, то її область - це період часу, протягом якого функція виконує функцію: поки функція працює, ім'я змінної існує , і пов'язаний зі своєю змінною, але після повернення функції ім'я змінної не існує.


3

Лексичний обсяг означає, що функція шукає змінні в контексті, де вона була визначена, а не в області безпосередньо навколо неї.

Подивіться, як працює лексичний обсяг у Lisp, якщо ви хочете більш детально. Вибрана відповідь Кайла Кроніна в динамічних та лексичних змінних у Common Lisp набагато чіткіша, ніж відповіді тут.

Випадково я дізнався про це лише в класі Lisp, і це трапляється застосувати і в JavaScript.

Я запустив цей код у консолі Chrome.

// JavaScript               Equivalent Lisp
var x = 5;                //(setf x 5)
console.debug(x);         //(print x)
function print_x(){       //(defun print-x ()
    console.debug(x);     //    (print x)
}                         //)
(function(){              //(let
    var x = 10;           //    ((x 10))
    console.debug(x);     //    (print x)
    print_x();            //    (print-x)
})();                     //)

Вихід:

5
10
5

3

Лексична область в JavaScript означає, що змінна, визначена поза функцією, може бути доступною всередині іншої функції, визначеної після оголошення змінної. Але навпаки не вірно; змінні, визначені всередині функції, не будуть доступні поза цією функцією.

Ця концепція широко використовується при закритті JavaScript.

Скажімо, у нас є наведений нижче код.

var x = 2;
var add = function() {
    var y = 1;
    return x + y;
};

Тепер, коли ви зателефонуєте add () ->, це надрукує 3.

Отже, функція add () отримує доступ до глобальної змінної, xяка визначена перед методом add. Це називається завдяки лексичному обстеженню в JavaScript.


Поміркуйте, що фрагмент коду призначений для мови з динамічним діапазоном. Якщо add()функція, де викликується відразу за вказаним фрагментом коду, вона також надрукує 3. Лексичне масштабування не означає просто, що функція може отримати доступ до глобальних змінних за межами локального контексту. Отже, приклад коду насправді не допомагає показати, що означає лексичне визначення. Показ лексичного обстеження в коді дійсно потребує зустрічного прикладу або принаймні пояснення інших можливих тлумачень коду.
C Перкінс

2

Лексична область стосується лексики ідентифікаторів (наприклад, змінних, функцій тощо), видимих ​​з поточного положення в стеку виконання.

- global execution context
    - foo
    - bar
    - function1 execution context
        - foo2
        - bar2
        - function2 execution context
            - foo3
            - bar3

foo і bar завжди знаходяться в лексиці доступних ідентифікаторів, оскільки вони глобальні.

Коли function1виконується, він має доступ до лексики foo2, bar2, foo, і bar.

Коли function2виконується, він має доступ до лексики foo3, bar3, foo2, bar2, foo, і bar.

Причина, що глобальна та / або зовнішня функції не мають доступу до внутрішніх ідентифікаторів функцій, полягає в тому, що виконання цієї функції ще не відбулося, і тому жоден з її ідентифікаторів не був виділений в пам'ять. Більше того, щойно внутрішній контекст виконується, він видаляється із стеку виконання, тобто всі його ідентифікатори були зібрані сміттям і більше не доступні.

Нарешті, саме тому вкладений контекст виконання ВЖЕ завжди може отримати доступ до контексту виконання його предків, і, отже, він має доступ до більшого лексикону ідентифікаторів.

Подивитися:

Особлива подяка @ robr3rd за допомогу у спрощенні наведеного визначення.


1

Ось інший кут у цьому питанні, який ми можемо досягти, зробивши крок назад і подивившись на роль масштабування в більш широких рамках інтерпретації (запуск програми). Іншими словами, уявіть, що ви будували інтерпретатор (або компілятор) для мови і відповідали за обчислення результатів, дали програму та деякий вклад до неї.

Інтерпретація передбачає відстеження трьох речей:

  1. Стан - а саме змінні та посилання на пам'ять у купі та стеку.

  2. Операції в цьому стані, а саме кожен рядок коду у вашій програмі

  3. Середа , в якій дана операція виконується , а саме - проекція стану на операцію.

Інтерпретатор починається з першого рядка коду програми, обчислює його середовище, запускає рядок у цьому середовищі та фіксує його вплив на стан програми. Потім слід керувати потоком програми для виконання наступного рядка коду та повторює процес до кінця програми.

Спосіб обчислення середовища для будь-якої операції здійснюється за допомогою формального набору правил, визначених мовою програмування. Термін "зв'язування" часто використовується для опису відображення загального стану програми до значення в навколишньому середовищі. Зауважимо, що під загальним станом ми маємо на увазі не глобальну державу, а скоріше загальну суму кожного досяжного визначення у будь-якій точці виконання).

Це рамка, в якій визначена проблема масштабування. Тепер до наступної частини наших варіантів.

  • Як реалізатор інтерпретатора, ви можете спростити своє завдання, зробивши середовище максимально наближеним до стану програми. Відповідно, середовище рядка коду було б просто визначене оточенням попереднього рядка коду з ефектами цієї операції, застосованої до нього, незалежно від того, чи був попередній рядок призначенням, викликом функції, поверненням з функції, або керуюча структура, така як цикл час.

Це суть динамічного масштабування , де середовище, в якому працює будь-який код, пов'язане зі станом програми, визначеним контекстом його виконання.

  • Або ви можете придумати програміста, який використовує вашу мову та спростити його завдання відстежувати значення, які може приймати змінна. Занадто багато шляхів і занадто багато складностей, пов'язаних з обґрунтуванням результату, сукупністю минулого виконання. Лексичне оцінювання допомагає зробити це, обмеживши поточне середовище частиною стану, визначеним у поточному блоці, функції чи іншій одиниці області дії, та його батьківською (тобто блоком, що охоплює поточний тактовий годинник, або функцією, яка викликала теперішню функцію).

Іншими словами, з лексичним розмахом середовище, яке бачить будь-який код, пов'язане із станом, пов'язаним із сферою дії, визначеною явно мовою, наприклад блоком або функцією.


0

Стародавнє питання, але ось мій погляд на це.

Лексична (статична) область стосується сфери змінної у вихідному коді .

Такою мовою, як JavaScript, де функції можна передавати навколо, додавати та повторно приєднувати до різних об'єктів, можливо, ви хочете, що цей обсяг залежатиме від того, хто викликає функцію в той час, але це не так. Зміна області застосування таким чином буде динамічною областю, і JavaScript цього не робить, за винятком випадків, якщо вони thisпосилаються на об'єкт.

Для ілюстрації пункту:

var a='apple';

function doit() {
    var a='aardvark';
    return function() {
        alert(a);
    }
}

var test=doit();
test();

У прикладі змінна aвизначена глобально, але у тіні doit()функція є тіньовою . Ця функція повертає ще одну функцію, яка, як бачите, покладається наa змінну поза її власною областю.

Якщо запустити це, ви побачите, що використовуване значення є aardvark, а не appleяке, хоча воно і входить до сфери використанняtest() функції, не входить до лексичної сфери вихідної функції. Тобто, використовувана область - це сфера, яка відображається у вихідному коді, а не область, де функція фактично використовується.

Цей факт може мати дратівливі наслідки. Наприклад, ви можете вирішити, що простіше організувати свої функції окремо, а потім використовувати їх, коли настане час, наприклад, в обробці подій:

var a='apple',b='banana';

function init() {
  var a='aardvark',b='bandicoot';
  document.querySelector('button#a').onclick=function(event) {
    alert(a);
  }
  document.querySelector('button#b').onclick=doB;
}

function doB(event) {
  alert(b);
}

init();
<button id="a">A</button>
<button id="b">B</button>

Цей зразок коду робить один з кожного. Ви можете бачити, що завдяки лексичному оцінці кнопка Aвикористовує внутрішню змінну, а кнопкаB - ні. Ви можете закінчити функції гніздування більше, ніж хотілося б.

До речі, в обох прикладах ви також помітите, що внутрішні лексично змінені змінні зберігаються, навіть незважаючи на те, що функція, що містить функцію, виконала свій хід. Це називається закриттям і стосується доступу вкладеної функції до зовнішніх змінних, навіть якщо зовнішня функція закінчена. JavaScript повинен бути достатньо розумним, щоб визначити, чи не потрібні ці змінні, і якщо ні, чи зможе їх збирати сміття.


-1

Я зазвичай вчуся на прикладі, і ось трохи:

const lives = 0;

function catCircus () {
    this.lives = 1;
    const lives = 2;

    const cat1 = {
        lives: 5,
        jumps: () => {
            console.log(this.lives);
        }
    };
    cat1.jumps(); // 1
    console.log(cat1); // { lives: 5, jumps: [Function: jumps] }

    const cat2 = {
        lives: 5,
        jumps: () => {
            console.log(lives);
        }
    };
    cat2.jumps(); // 2
    console.log(cat2); // { lives: 5, jumps: [Function: jumps] }

    const cat3 = {
        lives: 5,
        jumps: () => {
            const lives = 3;
            console.log(lives);
        }
    };
    cat3.jumps(); // 3
    console.log(cat3); // { lives: 5, jumps: [Function: jumps] }

    const cat4 = {
        lives: 5,
        jumps: function () {
            console.log(lives);
        }
    };
    cat4.jumps(); // 2
    console.log(cat4); // { lives: 5, jumps: [Function: jumps] }

    const cat5 = {
        lives: 5,
        jumps: function () {
            var lives = 4;
            console.log(lives);
        }
    };
    cat5.jumps(); // 4
    console.log(cat5); // { lives: 5, jumps: [Function: jumps] }

    const cat6 = {
        lives: 5,
        jumps: function () {
            console.log(this.lives);
        }
    };
    cat6.jumps(); // 5
    console.log(cat6); // { lives: 5, jumps: [Function: jumps] }

    const cat7 = {
        lives: 5,
        jumps: function thrownOutOfWindow () {
            console.log(this.lives);
        }
    };
    cat7.jumps(); // 5
    console.log(cat7); // { lives: 5, jumps: [Function: thrownOutOfWindow] }
}

catCircus();

-1

Ця тема сильно пов'язана із вбудованою bindфункцією та введена у функції ECMAScript 6 Arrow . Це було дуже прикро, тому що для кожного нового методу "класу" (фактично функція), який ми хотіли використати, ми повинні були bindце зробити, щоб мати доступ до області застосування.

JavaScript за замовчуванням не встановлює його обсяг thisна функції (вона не встановлює контекст на this). За замовчуванням ви повинні чітко сказати, який контекст ви хочете мати.

Функції стрілки автоматично набувають так звану лексичну область (мають доступ до визначення змінної у її блоці, що містить). При використанні функцій стрілки вона автоматично прив'язується thisдо місця, де в першу чергу була визначена функція стрілки, а контекст цієї функції стрілки - її містить блок.

Подивіться, як це працює на практиці на найпростіших прикладах нижче.

Перед функціями стрілки (без лексичного діапазону за замовчуванням):

const programming = {
  language: "JavaScript",
  getLanguage: function() {
    return this.language;
  }
}

const globalScope = programming.getLanguage;
console.log(globalScope()); // Output: undefined

const localScope = programming.getLanguage.bind(programming);
console.log(localScope()); // Output: "JavaScript"

За допомогою функцій зі стрілками (лексичний обсяг за замовчуванням):

const programming = {
  language: "JavaScript",
  getLanguage: function() {
    return this.language;
  }
}

const arrowFunction = () => {
    console.log(programming.getLanguage());
}

arrowFunction(); // Output: "JavaScript"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.