Область действия, контекст выполнения, это, закрытие основ JS

JavaScript
Область действия, контекст выполнения, это, закрытие основ JS

Объем, контекст выполнения, это и закрытие JS — общие темы, и они также невежественны для новичков. Конечно, даже если вы ветеран, вы можете не понимать этих концепций досконально.

область действия и контекст выполнения

Объем:

Область видимости в js — это лексическая область видимости, которая определяетсякогда функция объявленаОн определяется местоположением (в отличие от лексической области видимости, динамическая область действия подтверждается при выполнении функции, js не имеет динамической области видимости, но в js это очень похоже на динамическую область видимости).Лексическая область видимости генерируется на этапе компиляции, это набор правил доступа для идентификаторов внутри функций.В конце концов, область видимости — это просто «пустое пространство», в котором нет реальных переменных, но которые определяют правила доступа к переменным.

цепочка прицеловПо сути, это список указателей на переменные объекты, которые ссылаются только на фактические переменные объекты и не содержат их. Цепочка областей видимости определяет набор правил продолжения запроса по цепочке областей видимости, когда переменная недоступна в текущем контексте.

Контекст выполнения:

контекст выполнения означаетКогда функция вызываетсяОбъект переменной, сгенерированный в стеке выполнения, мы не можем получить прямой доступ к этому объекту переменной, но мы можем получить доступ к переменным,thisобъект и т. д. Например:

let fn, bar; // 1、进入全局上下文环境
bar = function(x) {
  let b = 5;
  fn(x + b); // 3、进入fn函数上下文环境
};
fn = function(y) {
  let c = 5;
  console.log(y + c); //4、fn出栈,bar出栈
};
bar(10); // 2、进入bar函数上下文环境

Каждый раз, когда вызывается функция, в верхней части стека выполнения будет генерироваться новый контекст выполнения, и движок JavaScript будет обрабатывать их в стеке, который мы называем стеком вызова функции (стеком вызовов). Нижняя часть стека всегда является глобальным контекстом, а вершина стека — это текущий активный исполняемый контекст, также известный как активный объект (текущий контекст выполнения, синий блок на рисунке), который отличается от приостановленной переменной. объект внизу (контекст выполнения).

Разница: область действия — это набор правил доступа для идентификаторов внутри функции, которые определяются при объявлении функции, а контекст выполнения — это среда для ряда переменных, генерируемых при выполнении функции. Один генерируется, когда он определен, а другой генерируется, когда он выполняется.

понимать выполнение функции

Процесс выполнения функции разделен на две части, одна часть используется для генерации контекста выполнения, определения точки этого, объявления переменных и генерации цепочки областей видимости; другая часть предназначена для выполнения кода построчно по порядку.

  • Установление фазы контекста выполнения (происходит при вызове функции && до выполнения кода в теле функции)
  1. Генерировать объекты переменных, порядок: создать объект аргументов --> создать объявление функциональной функции --> создать объявление переменной var
  2. Создать цепочку областей действия
  3. Определите точку этого
  • этап выполнения функции
  1. Выполнять код строка за строкой последовательно, выполнять присваивание переменной при встрече с операцией присваивания, выполнять вызов ссылки на функцию при встрече с вызовом функции, выполнять условное суждение и вычисление выражения при встрече с условным суждением и выражением и т. д.

это указывает на

о jsthisКлючевые слова, помню, первый контакт был, когда я работал над фронтендом полгода-год (ха-ха, никак, я такой). В то время Брат Сюй (босс Java) научил меня связыватьclickкогда событиеthisПередайте его обработчику событий, например<button onclick="handle(this)">确认</button>, Я был ошеломлен,thisЧто за черт? ! С тех пор я официально начал свой трехлетний болезненный путь JS: инкапсуляция, замыкание, объектно-ориентированное, наследование и так далее.thisНа самом деле существует только четыре вида направлений:

let fn = function(){
  alert(this.name)
}
let obj = {
  name: '',
  fn
}
fn() // 方法1
obj.fn() // 方法2
fn.call(obj) // 方法3
let instance = new fn() // 方法4
  1. Вызов функции непосредственно в методе 1fn(), такой способ вызова похож на голого командира,thisнаправлениеwindow(в строгом режиме даundefined).
  2. Метод 2 — точечный вызовobj.fn(),В настоящее времяthisнаправлениеobjобъект. точка вызоваthisОтносится к объекту, предшествующему точке.
  3. Использование в методе 3callфункция положитьfnсерединаthisуказывает на первый параметр, вотobj. то есть использоватьcall,apply,bindфункция можетthisПеременная указывает на первый параметр.
  4. используется в методе 4newсоздал экземпляр объектаinstance, тогдаfnсерединаthisуказывает на экземплярinstance.

Что делать, если несколько правил выполняются одновременно? На самом деле приоритет вышеперечисленных четырех правил возрастает:

fn() < obj.fn() < fn.call(obj) < new fn()

первый,newВызов имеет наивысший приоритет, пока естьnewключевые слова,thisуказывает на сам экземпляр; тогда, если неnewключевые слова, естьcall、apply、bindфункция, тоthisуказывает на первый параметр, то если нетnew、call、apply、bind,Толькоobj.foo()Этот метод вызова точки,thisНаведите на объект перед точкой, наконец, полированный командирfoo()Этот способ вызова,thisнаправлениеwindow(в строгом режиме даundefined).

В es6 были добавлены стрелочные функции, и самая большая особенность стрелочных функций заключается в том, что у них нет собственныхthis、arguments、super、new.target, а стрелочная функция не имеет объекта-прототипаprototypeнельзя использовать в качестве конструктора (newФункция стрелки сообщит об ошибке).потому что у меня нет своегоthis, поэтому в стрелочной функцииthisНа самом деле, это относится к содержащей функцииthis. Будь то точечный вызов илиcallвызов, не может изменить функцию стрелкиthis.

Закрытие

Закрытие js — это кошмар новичка.В первые три года изучения js я просмотрел бесчисленное количество постов в блогах и искал концепцию замыкания, но в итоге ничего не нашел. Замыкания определяются в MDN следующим образом: Замыкание — это комбинация функции и лексического окружения, в котором эта функция объявлена.

какие? Вы можете говорить по-человечески?

Долгое время я застрял с поверхностным пониманием закрытия как «функция, определенная внутри функции». На самом деле это только одно из необходимых условий для закрытия. Это было не до тех пор, пока я прочитал определение закрытия в первом объеме «JavaScript вы не знаете» Кайл, что я вдруг понял:

Закрытие происходит, когда функция может запомнить и получить доступ к лексической области видимости, в которой она находится.

let single = (function(){
  let count = 0
  return {
    plus(){
      count++
      return count
    },
    minus(){
      count--
      return count
    }
  }
})()
single.plus() // 1
single.minus() // 0

Это одноэлементный шаблон, этот шаблон возвращает объект и присваивает его переменнойsingle,Переменнаяsingleсодержит две функцииplusа такжеminus, и обе функции используют переменные в своей лексической области видимости.count. при нормальных обстоятельствахcountи контекст выполнения, в котором он расположен, будет уничтожен в конце выполнения функции, но из-заcountвсе еще используется внешней средой, поэтому в конце выполнения функцииcountИ контекст выполнения, в котором он находится, не будет уничтожен, что приведет к замыканию. каждый звонокsingle.plus()илиsingle.minus(), это изменитcountПеременные изменяются, и эти две функции поддерживают ссылку на лексическую область видимости, в которой они находятся.

Замыкания — это на самом деле особый вид функций, которые могут обращаться к переменным внутри функции, а также сохранять значения этих переменных в памяти и не очищаться механизмом сборки мусора после вызова функции.

Посмотрите на классику Amway:

// 方法1
for (var i = 1; i <= 5; i++) {
  setTimeout(function() {
    console.log(i)
  }, 1000)
}
// 方法2
for (let i = 1; i <= 5; i++) {
  setTimeout(function() {
    console.log(i)
  }, 1000)
}

В методе 1 в цикле задаются пять таймеров, через одну секунду будет выполнена функция обратного вызова в таймере и будет напечатана переменная.iценность . Излишне говорить, что секундой позжеiувеличилось до 5, поэтому таймер печатает 5 пять раз. (Переменная в текущей области не найдена в таймереi, поэтому по цепочке областей видимости в глобальной области видимостиi)

Способ 2, из-за es6letсоздает локальную область, поэтому цикл устанавливает пять областей, а переменные в пяти областяхiРаспределение 1-5, и в каждой области установлен таймер, и переменная печатается на одну секунду позжеiценность . Через одну секунду таймеры находят переменные из соответствующих родительских областей.iсоставляет 1-5. Это новый способ использования замыканий для разрешения исключений переменных в циклах.

наконец

Я действительно не могу учиться.