От определения до выполнения, двигатель JS выполняет много работы по инициализации на уровне реализации. Поэтому перед изучением рабочего механизма двигателя JS нам необходимо ввести несколько связанных концепций: стек среды выполнения, глобальные объекты, среда выполнения, переменные объекты, активные объекты, цепочки объема и объема и т. Д. Эти концепции являются основными компонентами работы двигателя JS. Цель этой статьи состоит не в том, чтобы объяснить вам каждую концепцию в изоляции, а проанализировать ее с помощью простой демонстрации, объясняя детали двигателя JS от определения до исполнения, и роль, которую эти концепции играют в нем.
var x = 1; // Определить глобальную переменную xfunction a (y) {var x = 2; // Определить локальную переменную x Функция b (z) {// определить внутреннюю функцию b console.log (x+y+z); } return b; // вернуть ссылку на функцию b} var c = a (1); // выполнить a, return bc (1); // Выполнить функцию bЭто демонстрация является закрытием, и результат выполнения составляет 4. Ниже мы проанализируем рабочий механизм двигателя JS на три этапа: глобальная инициализация, функция выполнения A и функция выполнения B :
1. Глобальная инициализация
Когда двигатель JS входит в исполняемый кусок кода, он должен выполнить следующие три задачи инициализации:
Во -первых, создайте глобальный объект (глобальный объект). Существует только одна глобальная копия этого объекта, его свойства можно получить в любом месте, и его существование будет сопровождать весь жизненный цикл приложения. При создании глобального объекта обычно используются объекты JS, такие как математика, строка, дата, документ, используются в качестве их свойств. Поскольку этот глобальный объект не может быть доступен непосредственно по имени, есть еще одно окно свойства, и он указывает на окно на себя, так что глобальный объект можно получить через окно. Общая структура использования псевдокода для моделирования глобальных объектов заключается в следующем:
// Создать глобальный объект var globalobject = {math: {}, string: {}, date: {}, document: {}, // dom Operation ... Window: This // Попустите атрибут окна на себя}Затем двигатель JS должен создать стек контекста выполнения. В то же время он также должен создать глобальный контекст выполнения EC и подтолкнуть эту глобальную среду выполнения EC в стек среды выполнения. Функция стека среды выполнения состоит в том, чтобы гарантировать, что программа может быть выполнена в правильном порядке. В JavaScript каждая функция имеет свою собственную среду выполнения. При выполнении функции среда выполнения функции будет выдвинута в верхнюю часть стека среды выполнения и получить права на выполнение. Когда эта функция выполняется, ее среда выполнения удаляется из вершины стека, а право выполнения возвращается в предыдущую среду выполнения. Мы используем псевдокод для моделирования взаимосвязи между стеком среды выполнения и EC:
var ecstack = []; // Определить стек среды выполнения, аналогичный массиву var ec = {}; // Создать пространство выполнения, // Спецификация ECMA-262 не определяет структуру данных EC, вы можете понять его как кусок пространства, выделенного в памяти ecstack.push (ec); // введите функцию и нажмите среду выполнения ecstack.pop (ec); // после возвращения функции удалите среду выполненияНаконец, двигатель JS также создает глобальный объект переменной (объект VARIBALE), связанный с EC и точками VO для глобального объекта. VO не только содержит исходные свойства глобального объекта, но также включает переменную x и функцию определенной глобально. В то же время, при определении функции A, внутренний прибор атрибута также добавляется в A и Points Scope к Vo. Когда каждая функция будет определена, будет создан атрибут области, связанный с ней, а область всегда указывает на среду, в которой определяется функция. Структура Ecstack в настоящее время выглядит следующим образом:
Ecstack = [// Среда выполнения стека EC (g) = {// Глобальная среда выполнения vo (g): {// определить глобальный объект переменной ... // Содержит исходные атрибуты глобального объекта x = 1; // определить переменную x a = function () {...}; // Определить функцию aa [[[scope]] = this; // Определите область применения и назначить значение самому vo}}];2. Выполнить функцию a
Когда выполнение входит (1), двигатель JS должен сделать следующее:
Во -первых, двигатель JS создаст среду выполнения EC функции A, а затем EC подтолкнет его к вершине стека среды выполнения и получит права на выполнение. В настоящее время в стеке среды выполнения есть две среды выполнения, а именно в глобальной среде выполнения и функции среды выполнения. Среда выполнения A находится в верхней части стека, а глобальная среда выполнения находится в нижней части стека. Затем создайте цепочку функции областей A. В JavaScript каждая среда выполнения имеет свою собственную цепочку областей для разрешения идентификатора. Когда создается среда выполнения, ее цепочка областей инициализируется как объект, содержащийся в объеме выполненной в настоящее время функции.
Затем двигатель JS создаст активный объект (объект активации) AO текущей функции. Активный объект здесь играет роль переменного объекта, но он по -разному называется функцией (вы можете думать, что переменная объект является общей концепцией, а активный объект - это его ветвь). AO содержит формальные параметры функции, объект аргументов, этот объект, а также определения локальных переменных и внутренних функций, а затем AO будет подтолкнут к вершине цепочки объема. Следует отметить, что при определении функции B двигатель JS также добавит атрибут Scope к B и точечной областям в среду, в которой определяется функция B. Окружающая среда, в которой определяется функция B, является активным объектом A AO, а AO находится на передней части связанного списка. Поскольку связанный список имеет характеристики конечного соединения, объем функции B указывает на всю цепочку областей A. Давайте посмотрим на структуру Ecstack в настоящее время:
Ecstack = [// Стоимость среды выполнения ec (a) = {// a Environment recument excument [scope]: vo (g), // vo - это глобальный объект переменной ao (a): {// Создать активный объект y: 1, x: 2, // определить локальную переменную x b: function () {}, // определить функцию bb bb [[сфера] = это; // Это относится к самому АО, и АО находится на вершине ScopeChain, поэтому B [[Scope]] указывает на все аргументы цепочки объема: [], // Аргументы, которые мы получаем в функции, являются аргументами в AO: окно // Это в функции указывает на объект окна Caller}, Scopechain: <AO (A), [область полной области], и/////nickse incopecifize as a a a [ao). Затем AO добавляется в верхнюю часть цепи прицела. В настоящее время цепочка областей A: AO (a)-> vo (g)}, ec (g) = {// Глобальная среда выполнения vo (g): {// Создание объекта глобальной переменной ... // Содержит исходные атрибуты глобального объекта x = 1; // Определить переменную x a = function () {...}; // Определите функцию aa [[[Scope]] = this; // Определить область A, a [[[Scope]] == vo (g)}}];3. Выполнить функцию B
После выполнения функции A ссылка на B возвращается и присваивается переменной C. Выполнение C (1) эквивалентна выполнению B (1). Двигатель JS должен выполнить следующие задачи:
Сначала, как и выше, создайте среду выполнения EC функции B, а затем подтолкните ЕС к вершине стека среды выполнения и получите права на выполнение. В настоящее время в стеке среды выполнения существует две среды выполнения, а именно в глобальной среде выполнения и среда выполнения функции B. Среда выполнения B находится в верхней части стека, а глобальная среда выполнения находится в нижней части стека. (Примечание: когда функция A возвращает A, среда выполнения A будет удалена из стека, оставляя только глобальную среду выполнения), создайте цепочку функции B и инициализируйте его в объект, содержащемся в объеме функции B, то есть цепочка областей A., наконец, создайте активное объект функции B, и используйте параметры z, объект аргументов и этот объект B в качестве свойств. В настоящее время Ecstack станет таким:
Ecstack = [// ecure Environment Stack Ec (b) = {// Создать среду выполнения B и находится в верхней части цепочки объема [Scope]: AO (a), // указывать на цепочку функции Acte A, AO (a)-> vo (g) var ao (b) = {// Создание активного объекта функции b z: 1, аргументы: [], это: окна} Scopechain: <AO (b), B [[Scope]]> // Связанный список инициализируется в B [[[Scope]], а затем AO (B) добавляется в заголовок связанного списка. В настоящее время цепочка применения B: AO (B)-> AO (a) -vo (g)}, EC (a), // среда выполнения A была удалена из верхней части стека, EC (g) = {// Глобальная среда выполнения vo: {// определить глобальный переменный объект ... // Содержит оригинальные атрибуты глобального объекта x = 1; // определить переменную x a = function () {...}; // Определить функцию aa [[[scope]] = this; // Определить область A, a [[[Scope]] == vo (g)}}];Когда функция B выполняет «x+y+z», необходимо проанализировать три идентификатора x, y и z один за другим. Процесс анализа придерживается правил поиска переменной: сначала выясните, существует ли атрибут в вашем активном объекте. Если это существует, прекратите искать и вернуться; Если его не существует, продолжайте искать сверху вдоль цепочки областей, пока она не найдена. Если переменная не найдена во всей цепочке областей, верните «неопределенную». Из приведенного выше анализа мы видим, что цепочка функции B прицел следующая:
Ao (b)-> ao (a)-> vo (g)
Следовательно, переменная x будет найдена в AO (a) и не будет искать x в vo (g), переменная y будет найдена в Ao (a), а переменная z будет найдена в его собственной AO (b). Таким образом, результат выполнения: 2+1+1 = 4.
Простое резюме
После понимания рабочего механизма двигателя JS мы не можем просто оставаться на уровне понимания концепции, но использовать его в качестве основного инструмента для оптимизации и улучшения нашего кода в реальной работе, повышения эффективности выполнения и генерирования фактической ценности. Возьмите механизм переменного поиска в качестве примера. Если ваш код глубоко вложен, и каждый раз, когда вы обращаетесь к глобальной переменной, двигатель JS будет искать всю цепочку областей. Например, существует эта проблема с объектами окна и документов в нижней части цепочки объема. Поэтому мы можем выполнить много оптимизации производительности, и, конечно, есть и другие аспекты оптимизации. Я не буду вдаваться в подробности здесь. Эта статья просто рассматривается как совет!
по @一竞 2015
Выше всего содержание этой статьи. Я надеюсь, что это будет полезно для каждого обучения, и я надеюсь, что все будут поддерживать Wulin.com больше.