Как писать качественные функции — сбить гору и встряхнуть тигра

JavaScript

Тысяча читателей, тысяча Гамлетов.

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

введение

Как писать качественные функции - сложный вопрос. У разных людей есть свое мнение о качественных функциях. Здесь я всесторонне объясню некоторые из своих личных мнений о том, как писать качественные функции. Взгляды могут быть недостаточно полными, и могут быть некоторые неправильные мнения. Добро пожаловать, чтобы обсудить вместе. Так же, как люди, которые живут жизнью, маленькие шумы всегда будут появляться непреднамеренно, и включающее сердце - лучшее.best practice.

Стиль письма

Ведение блогов имеет тенденцию к потоку сознания (поток ерунды), я пишу в соответствии с тем, что думаю, и я не буду подробно объяснять определенный момент знания.Если вам нужно обсудить подробно, вы можете добавить меня в WeChat в конце статья.

Начнем, закончу тремя статьямиКак писать качественные функцииэта серия.

В трех статьях я объясню, как писать качественные функции с учетом следующих аспектов.

  • функция (все возможно)
  • имя функции
  • аннотация функции
  • сложность функции
  • Надежность функций (защитное программирование)
  • Входные и выходные параметры функции (возврат)
  • Как использовать функциональное программирование, чтобы открыть две линии функций
  • Как использовать шаблоны проектирования, чтобы сделать функции более мощными
  • пиши правильноV8Что такое дружественная функцияstyle
  • Функциональные фантазии фронтенд-инженеров

Начнем глупости: ШепотомBB, можете сначала поставить лайк и поощрить (подарить волну духовного поощрения).

PS: Тот, кто писал статьи, знает, что написать хорошую статью непросто и отнимает много сил.После написания блога самое большое душевное удовлетворение — это положительная похвала от маленького партнера. Привет, на самом деле эта серия уже написана.Я изначально хотел дописать статью, но прочитав ее,210 000 слов, слишком много, давайте разделим на три статьи.

В этой статье речь идет только о первом разделе函数, поймай вора сначала поймай короля, давай сыграем раунд функций, иди кXXXНа тарелке 😂.

функция (все возможно)

Слово «функция» означает, что все возможно.

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

Работая с функциями каждый день, задумывались ли вы когда-нибудь, какова цель функций? Давайте подумаем дальше, каков механизм выполнения функции? Кратко проанализируем его.

Назначение функции

Функции, безусловно, являются самым важным средством экономии места и повышения производительности из когда-либо изобретенных.

PS: Обратите внимание, его нет.

механизм выполнения функции

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

Как объяснить механизм выполнения функции?

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

Позвольте мне сымитировать вопрос на предварительном собеседовании: введитеurlЧто происходит после этого? (Ха-ха-ха-ха). Придумайте вопрос для интервью:

Выполнить функцию, что произойдет?

Обратитесь к приведенному ниже коду:

function say() {
  let str = 'hello world'
  console.log(str)    
}

Если бы вам задали этот вопрос для интервью, на сколько бы вы ответили?

прерывать5Подумайте об этом на минуту.

Что ж, перерыв закончился. Если бы мне пришлось отвечать на него, я бы примерно сказал:

Сначала я собираюсь создать функцию, стоп. если вы училисьC++, вы можете не говорить это, вы можете сказать это, я должен сначала открыть кучу памяти.

Поэтому я проанализирую три уровня от создания функции до выполнения функции и ее базовой реализации:

создать функцию

Функции не создаются просто так, вы хотите создать функцию, а когда вы создаете функцию, что происходит?

Ответ таков:

Шаг 1: Я хочу открыть новую динамическую память

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

Шаг 2: я создаю функциюsay, поместите код в тело этой функции в эту динамическую память.

Подумайте, как тело функции размещается в куче памяти? Очевидно, в виде строки. Зачем? Давайте взглянемsayКаков код тела функции, как показано ниже:

let str = 'hello world'
console.log(str)  

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

Шаг 3: Объявите в текущем контекстеsayФункции (переменные), объявления функций и определения выдвигаются на передний план

Обратите внимание, что ключевым моментом является текущий контекст, который мы можем понимать как контекстный стек (стек),sayОн помещается в стек (stack), а с правой стороны от него находится адрес памяти кучи, который используется для указания на тело функции в куче.

PS: Рекомендуется изучить структуру данных, части в стеке называются фреймами. Вы можете понять дерево DOM в стеке, фрейм понимается как узел, и каждый фрейм (узел) имеет свое имя и содержимое.

Шаг 4: Назначьте открытый адрес памяти кучи имени функцииsay

Ключевым моментом здесь является присвоение адреса кучи памяти имени функцииsay.

Я специально нарисовал на доске простую схему:

Объедините приведенную выше картинкуsayХранилище справа, а затем понять четыре вышеуказанных шага, это немного сентиментально?

Вы действительно понимаете операцию присваивания?

Здесь мне вдруг хочется упомянуть простое знание, которое является операцией присваивания, например, я присваиваю адрес памяти кучи имени функцииsay, так что это значит?

Многие могут не понять.На самом деле здесь все очень просто.На этом этапе операции присваивания с точки зрения принципов компоновки компьютера память делится на несколько областей,таких как область кода,область стека,область кучи и т.д.

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

Поэтому простое присваивание очень сложно в базовой реализации компьютера.Вот, возможно, с помощью языка ассемблера можно лучше понять истинное значение присваивания, например1 + 1Написанный на языке ассемблера, это следующий код:

start:
mov ax, 1
mov bx, 1
add ax, bx
end start;

Из приведенного выше кода мы видим, что1назначить наax, использовалmovинструкция. а такжеmovдаmoveАббревиатура для перемещения, которая также доказывает, что операция присваивания на самом деле является потоком данных или дескрипторами данных в адресной таблице.

PS: Итак, если это тип значения, он предназначен для прямой передачи (перемещения) данных в пространство для хранения указанного адреса памяти.

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

выполнить функцию

Шаг выполнения функции также очень важен.Что представляет собой процесс выполнения функции?Сейчас я буду использовать свое личное резюме, чтобы объяснить этот процесс.

Рассмотрим точку.

Мы знаем, что код тела функции хранится в куче памяти и находится в виде строки. Итак, если мы хотим выполнить код в куче памяти, первое, что нужно сделать, это сказать, что строка становится реальной.JSКод, это относительно легко понять, так же как сериализацию и десериализацию при передаче данных.

Вопрос 1: Почему существуют сериализация и десериализация? Вы можете подумать об этом сами, чем проще правда, тем больше за ней неординарных мыслей.

превратить строку в реальнуюJSкод

Как превратить строку вJSКод, здесь есть необходимые знания, то есть:

Каждый вызов функции создает кадр в стеке контекста функции.

Что такое стек?

Стек — это базовая структура данных, поэтому я не буду объяснять его здесь.Если вы не понимаете его, зайдите на Baidu и посмотрите.

Почему выполнение функции должно выполняться в стеке?

Наиболее важным моментом является то, что стек представляет собой структуру данных «первым пришел, последним вышел». Почему? Давайте посмотрим на кусок кода:

function f1() {
  let b = 1;
  function f2() {
    cnsole.log(b)
  }
  return f2
}

let fun = f1()
fun()

Я не буду объяснять это здесь, и продолжу смотреть вниз.

Что такое стек контекста функции?

Мы можем понять это так: стек контекста функции — это структура данных, независимо от того, что это такое, если вы узналиC++илиC, можно понимать какstruct(структура). Эта структура отвечает за управление выполнением функций с закрытой областью видимости переменных. Стек контекста функции генерируется во время работы программы, а кадр глобального контекста добавляется в стек в начале, который находится в нижней части стека.

начать выполнять функцию

Первое, что нужно понять:

Выполнение функции (вызов функции) выполняется в стеке.

ПоэтомуJSФункция может быть рекурсивной. Поскольку стек имеет расширенную структуру данных, ему дается рекурсивная способность.

Продолжая смотреть вниз, выполнение функции примерно состоит из следующих шагов:

Первый шаг: будет сформирована среда выполнения кода, которая также является стековой памятью

Здесь мы сначала рассмотрим несколько вопросов:

  • Что это за среда для выполнения кода?
  • Как распределяется эта память стека?
  • Как выглядит внутренняя часть этой памяти стека?

Шаг 2: Скопируйте сохраненную строку во вновь открытую память стека, чтобы сделать ее реальной.JSкод

Этот шаг легко понять.

Третий шаг: сначала присвойте значения формальным параметрам, а затем выполните продвижение переменных, например добавлениеvar functionВариативное продвижение.

Шаг 4: Выполните сверху вниз в этой недавно открытой области

Вопросы для размышления: Почему это выполняется сверху вниз?

Возвращает результат выполнения в текущую вызываемую функцию

Вопрос для размышления: Как вернуть результат выполнения в текущую вызываемую функцию?

Расскажите о базовой реализации

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

Самое важное объяснение замыкания в компьютерах

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

Цели следующие:

Пункт первый: превратить строки, хранящиеся в исходной памяти кучи, в настоящиеJSкод

Пункт второй: защитить приватные переменные стековой памяти от постороннего вмешательства

Этот защитный механизм выполнения функции в компьютере называется замыканием.

Некоторые люди могут не понять, почему это личное?

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

Как распределяется память стека?

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

Как выглядит внутренняя часть этой памяти стека?

Это действительно интересно, почему? Позвольте мне привести вам пример, вы пишете каждый деньreturnфраза, ты знаешьreturnосновная реализация? Вы пишете подпрограммы каждый день, так знаете ли вы, что лежит в основе подпрограмм?

Давайте посмотрим на картинку:

На приведенном выше рисунке показана структура стека вызова функции.Из структуры мы можем видеть, что находится внутри, например, фактические параметры, локальные переменные и адреса возврата.

См. код ниже:

function f1() {
  return 'hello godkun'    
}
let result = f1()
f2(result)

Основное значение приведенной выше строки кода заключается в следующем:f()После того, как функция будет выполнена в частной памяти стека, используйтеreturnПослеreturnПосле того, как результат выполнения передаетсяEAX(накопительный регистр), часто используемый для возвращаемых функцией значений. Если вы не знаете о реестре, вы можете найти и изучить его самостоятельно, поэтому я не буду говорить об этом здесь. Здесь я говорюReturn Addr,AddrОсновная цель состоит в том, чтобы позволить подпрограммам вызываться несколько раз.

См. код ниже:

function main() {
  say()
  // TODO:
  say()
}

Приведенный выше код, вmainВ функции выполняются множественные вызовы подпрограмм.say, в базовой реализации, путем сохраненияAddrИспользуется для сохранения начального адреса функции, когда первыйsayПосле завершения работы функцииAddrОн укажет на начальный рабочий адрес на случай, если подпрограмма будет вызываться много раз позже.

JSКак двигатель выполняет функцию

Выше я проанализировал механизм выполнения функции со многих аспектов, которые могут быть немного сложными для понимания. Теперь позвольте мне кратко проанализировать,JSКак движок выполняет функцию.

Я не буду делать колеса здесь, есть блог, написанный очень хорошо, я думаю от всего сердца, что я не смогу написать лучший блог, чем этот. Даже если я напишу это, я не думаю, что это необходимо. Однако этот блог слишком общий, и многие детали не упоминаются, здесь я разберу многие важные детали на основе этого блога.

адрес блога:

Узнайте, как работает движок JS

Теперь приступаю к разбору, код такой:

//定义一个全局变量 x
var x = 1 
function A(y) {
 //定义一个局部变量 x
  var x = 2
  function B(z) {
    //定义一个内部函数 B
    console.log(x + y + z)
  }
  //返回函数B的引用
  return B 
}
//执行A,返回B
var C = A(1)
//执行函数B
C(1)

PS: Я предлагаю вам сначала прочитать блог, чтобы узнать некоторые основные понятия, а затем прочитать мой анализ.

Приступаем к анализу:

воплощать в жизньAвремя функции

JSдвигатель построенESCstackСтруктура выглядит следующим образом:

короткое имяAкартина:

воплощать в жизньBвремя функции

JSдвигатель построенESCstackСтруктура выглядит следующим образом:

короткое имяBкартина:

Следующее начинается с наиболее важных личных идей.show time.

Как хранятся локальные переменные

Ядро смотрит на следующий код:

EC(B) = {
  [scope]:AO(A),
  var AO(B) = {
    z:1,
    arguments:[],
    this:window
  },
  scopeChain:<AO(B),B[[scope]]>  
}

это выполнениеB函数при созданииBСреда выполнения функции (структура объекта). EстьAO(B),ЭтоBАктивный объект функции.

ЭтоAO(B)с какой целью? фактическиAO(B)Это контент, на который указывает каждый узел связанного списка.

В то же время он также определяет[scope]Атрибут, мы можем понимать его как указатель,[scope]указал наAO(A),а такжеAO(A)это функцияAактивный объект.

Объект функциональной активности содержит локальные переменные, массивы параметров,thisАтрибуты. Вот почему вы можете использовать внутри функцииthisа такжеargumentsпричина.

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

такие как выполнениеBфункция, чтоBСвязанный список выглядит как AO(B) --> AO(A)

Но не забывайте,AФункция также имеет свой собственный связанный список, который представляет собой AO(A) --> VO(G). Таким образом, весь связанный список объединяется,BСвязанный список (область действия): AO(B) --> AO(A) --> VO(G)

Связанный список представляет собой замкнутый цикл, потому что после круга, когда вы возвращаетесь к себе, если вы еще не нашли его, то возвращайтесь назад.undefined.

Вопросы для размышления: вы можете подумать об именах [scope] и [[scope]] и почему они в такой форме.

пройти черезAфункциональныйECSчто мы можем увидеть

мы можем видеть,JSЯзык является языком со статической областью видимости, перед выполнением функции также определяется цепочка областей действия всей программы, начиная сAфункция на графикеBизB[[scope]]Вы можете видеть, что цепочка областей действия определена. В отличие отlispВид, который можно определить только во время выполнения.

Среда исполнения, что за существование контекстная среда

Структура данных среды выполнения представляет собой стековую структуру, которая, по сути, добавляет к массиву некоторые свойства и методы.

Среду выполнения можно использоватьECStackвыражать, понимать какECSack = []эта форма.

Стек (среда выполнения) специально используется для хранения различных данных, например, самый классический из них — хранение различных структур подданных при выполнении функции.

НапримерAСреда выполнения функцииEC(A). при выполнении функцииA, эквивалентноECStack.push[A], при принадлежности кAКогда эти вещи вставляют в стек, они будут обернуты в частную память стека.

Как формируется частный стек?Здесь задействован язык ассемблера.С точки зрения языка ассемблера вы обнаружите, что выделение памяти стека и различные преобразования структуры стека контролируются базовыми стандартами.

Итак, давайте снова обратимся к тому, что мы обычно называем контекстной средой,contextПодождите, на самом деле это ничем не отличается от среды выполнения, которую я объяснил выше.Если вы понимаете это таким образом, вы обнаружите, что у вас есть более глубокое понимание имен собственных, таких как контекст.

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

Включите режим Бога, чтобы видеть сквозьthis

thisПочему он определяется во время выполнения

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

СмотретьAфигура, выполнениеAфункция, толькоAфункция имеетthisсвойства, выполнитьBфункция, толькоBфункция имеетthisАтрибут, это подтвержденоthisСуществует только во время выполнения.

thisуказывая на правду

Давайте взглянемthisуказывает на,AПри вызове функции атрибутthisСобственностьwindowКvar C = A(1)передачаAПосле функции,AСреда выполнения функции ужеpopиз стека. выполнить в это времяC()выполняетBфункция,EC(B)уже на вершине стека,thisСтоимость свойстваwindowглобальные переменные.

пройти черезAфигура иBСравнение картинок, прямой показthisПрирода.看清真相,thisВот и все.

Суть области видимости — это узел в связанном списке.

Неважно, если ты не понимаешь, просто послушай меня.

пройти черезAфигура иBСравнение графиков, прямое уничтожение всех видов использования области видимости

СмотретьAфигура, выполнениеAфункция,BОбъем функции заключается в созданииAактивный объект функцииAO(A). Область видимости — это атрибут, атрибут, принадлежащий среде выполнения функции А, и его имя называется[scope].

[scope]Он указывает на объект действия функции.На самом деле, суть здесь в том, что каждый должен относиться к этому объекту функции как к области действия, но лучше понимать его как узел связанного списка.

Если вы можете понять это как узел связанного списка, то вы больше не будете незнакомы с тем, почему существует цепочка областей действия, и вы больше не будете путаться в разнице между областью действия и цепочкой областей действия. Непосредственно убивает все проблемы, связанные с областью действия.

PS: Bвоплощать в жизньBфункция, толькоBфункция имеетthisсвойства, которые также перекрестно подтвердилиthisСуществует только во время выполнения.

Суть цепочки областей действия — это связанный список

сначала сравнивAРисунок иBграфикаscopeChain, мы можем определить, что:

Цепочка областей действия — это, по сути, связанный список.Какая функция выполняется, связанный список инициализируется областью действия какой функции, а затем инициализируется область действия функции.[scope]Поместите его в начало таблицы, чтобы сформировать замкнутый связанный список.Поиск цепочки областей видимости осуществляется через связанный список.Если он не найден после кружка, то вернутьсяundefined.

Цепочка областей действия также оченьeasyиз.

Поднимите вас на новый уровень с помощью одного вопроса на собеседовании

Я решил привести еще один пример, это часто задаваемый вопрос на собеседовании, посмотрите на код ниже:

Первая программа выглядит следующим образом:

function kun() {
  var result = []
  for (var i = 0; i < 10; i++) {
    result[i] = function() {
      return i
    }
  }
  return result
}

let r = kun()
r.forEach(fn => {
  console.log('fn',fn())
})

Вторая программа выглядит следующим образом:

function kun() {
  var result = []
  for (var i = 0; i < 10; i++) {
    result[i] = (function(n) {
      return function() {
        return n
      }
    })(i)
  }
  return result
}

let r = kun()
r.forEach(fn => {
  console.log('fn', fn())
})

Каков будет вывод этих двух программ? и проанализируйте его принцип.

Все должны знать результаты вывода.Результаты следующие:

Первая программа, вывод10индивидуальный10:

Вторая программа, вывод0прибыть9:

Итак, вопрос в том, знаете ли вы его внутренний механизм?

  • частьcoderМогу только ответить на немедленный вызов, закрытие.
  • наиболееcoderМожет ответить на вопросы, связанные со сферой знаний.
  • очень малоcoder(Уровень большого босса) Его можно проанализировать по основным причинам.

Далее я покажу вам, какой анализ из основных основных причин.style.

Результат анализа 10 10

код показывает, как показано ниже:

function kun() {
  var result = []
  for (var i = 0; i < 10; i++) {
    result[i] = function() {
      return i
    }
  }
  return result
}

let r = kun()
r.forEach(fn => {
  console.log('fn',fn())
})

Как анализировать, прежде всего, мы должны понимать, что среда выполнения функции будет сгенерирована только при выполнении функции. Тогда согласно этому правилу мы можем знать, что после завершенияr = kun()когда,kunФункция выполняется только один раз, и соответствующийAO(kun). мы можем взглянутьAO(kun)Что, следующим образом:

AO(kun):{
  i = 10;
  kun = function(){...};
  kun[[scope]] = this;
}

В это время выполняетсяkun()Позже,iЗначение уже10.OK, самый критический момент ниже, пожалуйста, обратите внимание,kunФункция выполняется только один раз, что означает:

существуетkunФункцияAO(kun)серединаiсобственность10.

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

AO(kun) --> VO(G)

а такжеkunФункция была удалена из вершины стека, оставив толькоAO(kun), Обратите внимание, что:

здесьAO(kun)Представляет узел с указателями и данными, где указатель указывает наVO(G), данныеkunактивный объект функции.

Итак, возникает следующий вопрос, когда выполнятьresultЧто происходит, когда массив в ? Обратите внимание, что:

resultОбласть действия каждой функции в массиве была определена, как упоминалось выше,JS— это язык со статической областью видимости, в котором все области видимости определяются на этапе объявления программы.

Итак, зная это,resultЦепочка областей действия каждой функции в массиве выглядит следующим образом:

AO(result[i]) --> AO(kun) --> VO(G)

следовательноresultКогда каждая функция выполняется, ееiВсе значения просматриваются по этой цепочке областей видимости, и посколькуkunФункция выполняется только один раз, в результате чегоiЗначение – это окончательный результат, т.10. Таким образом, выход10индивидуальный10.

Таким образом, этоresultМножество10После объявления функции она имеет в общей сложности10Связанный список (цепочка областей), обаAO(result[i]) --> AO(kun) --> VO(G)эта форма, но10в цепочке масштабовAO(kun)все так же. Таким образом, результат состоит в том, что выход10индивидуальный10.

Фактически, благодаря приведенному выше объяснению он был проанализирован с точки зрения очень низкого уровня. Я также упомянул ключевые моменты, на которые необходимо обратить внимание. Давайте внимательно изучим это.

Давайте проанализируем вывод0прибыть9результат.

Выход анализа от 0 до 9

код показывает, как показано ниже:

function kun() {
  var result = []
  for (var i = 0; i < 10; i++) {
    result[i] = (function(n) {
      return function() {
        return n
      }
    })(i)
  }
  return result
}

let r = kun()
r.forEach(fn => {
  console.log('fn', fn())
})

Результат анализа10индивидуальный10ситуации, каждый должен что-то приобрести или почувствовать какое-то чувство, то вывод0прибыть9Как следует анализировать результаты? Позвольте мне сказать вам.

Прежде всего, он отличается от приведенного выше, в объявлении функцииkun, это уже было выполнено10Анонимная функция. Помните, что пока функция выполняется, будет создана среда выполнения функции. Значит, вECSВ стеке естьEC(kun)Среда исполнения, но с 10 анонимнымиEC(匿名)Среда выполнения, соответствующаяresultв массиве10функция.

Для конкретной ситуации отображения позвольте мне выразить это в псевдокоде:

Ниже приведена реализацияkunвремя функции.

ECSack = [
  EC(kun) = {
    [scope]: VO(G)
    AO(匿名1) = {
      i: 0,
      result[0] = function() {...// return i},
      arguments:[],
      this: window
    },
    scopeChain:<AO(kun), kun[[scope]]>
  },
  // .....
  EC() = [
    [scope]: AO(kun)
    AO(kun) = {
      i: 9,
      result[9] = function() {...// return i},
      arguments:[],
      this: window
    },
    scopeChain:<AO(kun), kun[[scope]]>
  ]
]

Вышеупомянутое просто выражено на структурированном языкеkunВнутренняя ситуация функции при ее объявлении, прежде всего, есть два момента, на которые следует обратить внимание.

Первый пункт: каждыйEC(kun)серединаAO(kun)серединаiЗначения атрибутов все разные.Например, через приведенное выше структурированное представление вы можете увидеть:

  1. result[0]Родительская среда выполнения функцииEC(kun),этоVO(kun)внутриiзначение0.
  2. result[9]Родительская среда выполнения функцииEC(kun),этоVO(kun)внутриiзначение9.
Помните, что «Ао(кун)» — это место для хранения. -->

Второй момент: про цепочку прицелов, т.е.scopeChain,resultФорма связанного списка функций в по-прежнему имеет следующую форму

AO(result[i]) --> AO(kun) --> VO(G)

Но разница в том, что адрес хранения соответствующего узла отличается, что эквивалентно10новыйAO(kun). и каждыйAO(kun)в содержимом узлаiЦенности не те.

Итак, вкратце:

воплощать в жизньresultв массиве10функция, иди10Различные списки, и каждый списокAO(kun)Узлы не одинаковы. каждыйAO(kun)в узлеiЦенности тоже разные.

Таким образом, вывод, наконец, отображается как0прибыть9.

Суммировать

Вы обнаружили, что если вы проанализируете и поймете снизу, многие вопросы на самом деле имеют очень разумный или приемлемый ответ для читателя.

Суммировать

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

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

Как уменьшить количество поисковых запросов по цепочке областей действия (связанному списку)

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

Как предотвратить переполнение стека

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

Я думаю, что мы должны много работать, чтобы добиться такого достижения:

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

Если вы можете это сделать, вы боитесь, что не сможете писать качественные функции?

Примечание

  • Постучите по горе и потрясите тигра немного сложно читать, если вы проанализируете это больше, вы поймете
  • Статья неизбежно неверна, пожалуйста, потерпите меня, добро пожаловать, чтобы указать на ошибки в комментариях и больше общаться

Ссылаться на

общаться с

В дальнейшем будут два других блога, а именно базовый и расширенный, вы можете следить за моим блогом Nuggets илиgithubполучать уведомления о последующих статьях серии.

Серия технических статей Nuggets резюмируется следующим образом: если вы считаете, что это хорошо, нажмите на звездочку, чтобы поощрить это.

github.com/godkun/blog

Я терминатор исходного кода, и обмен технической информацией приветствуется.

также может войтиГруппа звукозаписи Front-end RhapsodyПроведите мозговой штурм вместе. Если вы хотите добавить, потому что она заполнена, вы можете сначала добавить меня в друзья, и я приглашу вас присоединиться к группе.

Язык ветра

Сегодня веселый праздник, это не только Фестиваль Фонарей, где можно поедать шарики из клейкого риса и отгадывать загадки о фонариках, но и фестиваль, где программисты проводят всю ночь (Фестиваль Обезьян).

несмотря на то что20Номер, но ничего не говори, я желаю тебе, самый богатый человек, счастливого Праздника Фонарей в наступающем году (хе-хе).

Напоследок: уважайте оригинальность, пожалуйста, указывайте источник для перепечатки 😋