предисловие
Прекомпиляция, как следует из названия, заключается в выполнении некоторой работы по замене текста кода. Это первая работа, которую необходимо выполнить во всем процессе компиляции. Библия JavaScript — MDN прямо говорит, что JavaScript — это интерпретируемый, а не компилируемый язык, поэтому для JS не существует предварительной компиляции. Но людям нравится называть это предварительной компиляцией, и это не повредит.Ключ в том, почему люди думают, что в JS есть предварительная компиляция, и какое поведение JS заставляет людей думать, что он производит предварительную компиляцию? Давайте быстро поболтаем.
представлять
Перед выполнением кода компилятор сделает следующее:
этап разбора
- Причастие. состоит в том, чтобы разделить код на атомарные символы (токен)
- Перевести синтаксический анализ токенов в AST (Spanning Tree синтаксиса).
Второй этап анализа
3. Когда встречается оператор объявления, объявление будет передано в область видимости (scope) для создания привязки, выделения памяти и установки переменной в значение undefined или тела функции по умолчанию.
Затем вы можете выполнить код.Каждый раз, когда во время выполнения встречается присваивание или значение, привязка будет искаться из области видимости. Глядя на это с этой стороны, может быть, оно немного «предварительно скомпилировано»? Но на самом деле правильнее будет назвать это предварительной обработкой. Далее давайте взглянем на волну операций, которая больше всего похожа на прекомпиляцию — галантерею третьего шага.
«Предварительно скомпилированный»
Мой учитель рассказал мне эту шутку, прежде чем рассказать мне о соответствующих знаниях:
Я завис во время интервью из-за этого вопроса
var a = 100
function foo(){
console.log(a)
}
foo()
В: Почему значение вывода равно 100?
Ответ: Поскольку 100 присваивается a.
После того, как учитель закончил говорить, у меня закружилась голова, и я вообще не понял смысла шутки, а позже понял, что это исследование знаний о «прекомпиляции».
В целом, «предварительно скомпилированные» можно разделить на
- Создание объекта GO (глобальный объект) происходит при загрузке страницы.
- Создание объекта АО (объекта активации) происходит непосредственно перед выполнением функции.
Конкретные шаги заключаются в следующем:
全局预编译
1. 创建GO对象
2. 找变量声明,将变量声明作为GO对象的属性名,并赋值undefined
3. 找全局里的函数声明,将函数名作为GO对象的属性名,值赋予函数体
局部预编译
1. 创建一个AO对象
2. 找形参和变量声明,将形参和变量声明作为AO对象的属性名,值为undefined
3. 将实参和形参统一
4. 在函数体里找函数声明,将函数名作为AO对象的属性名,值赋予函数体
Так что на вопрос интервью в этом анекдоте следует ответить так:
首先,编译器创建一个GO对象
找到变量声明 var a
和函数声明 function foo(){}
将上面两个变量声明作为GO的属性名赋初值
GO{
a:undefined
foo:function(){}
}
然后运行第一行代码 a=100
在GO中将100赋值给a
再执行第五行代码运行foo函数
创建一个AO对象
在函数体内找变量声明和形参,(无)
再在函数体内找函数声明(无)
所以
AO{
}
完成后运行第三行代码,输出a
先在AO对象中寻找a的值,发现不存在,向外部作用域扩展,在GO对象中寻找a,发现a的值为100
输出100
Конечно, вопрос в анекдоте слишком простой, но он позволяет наглядно понять ход этой "прекомпиляции"
Теперь давайте рассмотрим упрощенную версию вопроса для собеседования и потренируем свои навыки:
global = 100
function fn() {
console.log(global);
global = 200
console.log(global);
var global = 300
}
fn()
Какова его логика и вывод? Благодаря пошаговому анализу мы можем узнать, что конкретный анализ должен быть таким:
GO: {
global: undefined => 100,
fn: function() {}
}
global = 100 // 没有声明的变量默认为全局变量,也会放到GO中
function fn() {
console.log(global); // 输出undefined
global = 200
console.log(global); // 输出200
var global = 300
}
AO: {
global: undefined => 200 => 300
}
fn()
На этом статья заканчивается, надеюсь, вам всем понравилось. Если есть какие-либо ошибки, добро пожаловать в область комментариев для получения рекомендаций.