Ответ 1
var a;
- фактически оператор объявления переменной. Когда функция определена, все объявленные в ней переменные обрабатываются до выполнения кода, поэтому вы можете использовать переменные еще до того, как фактическая строка объявления будет запущена во время выполнения. Это называется var
hoisting. Таким образом, независимо от того, сколько раз вы объявляете переменную, переменная объявляется только один раз.
В вашем случае вы определили a
как один из параметров функции, который привязан к текущей функции. И затем вы объявляете переменную с тем же именем. Поскольку a
уже объявлен в функции, как один из параметров, объявление var a;
будет проигнорировано.
Вот почему вы получаете why is this not undefined?
в консоли.
Вместо var a;
, скажем, у вас есть var a = 1;
, в этом случае переменная уже объявлена, но выражение присваивания будет оцениваться во время выполнения, а значение 1
будет присвоено a
. Таким образом, console.log
будет печатать 1
.
Это поведение объясняется в спецификации ECMA Script 5.1, в разделе 10.5 Активация связывания с подписью,
Если код является кодом функции, то
а. Пусть func - функция, внутренний метод [[Call]] инициировал выполнение кода. Пусть имена будут значением funcs Внутреннее свойство [[FormalParameters]].
б. Пусть argCount - количество элементов в args.
с. Пусть n - число 0.
д. Для каждого String argName в именах, в порядке списка do
я. Пусть n - текущее значение n плюс 1.
II. Если n больше argCount, пусть v есть undefined, иначе v - значение n-го элемента args.
III. Пусть argAlreadyDeclared является результатом вызова envs метода HasBinding, передающего argName в качестве аргумента.
IV. Если argAlreadyDeclared является ложным, вызовите envs CreateMutableBinding конкретный метод, передающий argName как аргумент.
v. Вызовите envs SetMutableBinding конкретный метод, передавая argName, v и strict в качестве аргументов.
....
Для каждого VariableDeclaration и VariableDeclarationNoIn d в коде в исходном текстовом порядке выполните
а. Пусть dn - Идентификатор в d.
б. Пусть varAlreadyDeclared является результатом вызова envs метода HasBinding, передающего dn в качестве аргумента.
с. Если varAlreadyDeclared является ложным, то
я. Вызов envs CreateMutableBinding метод, передающий dn и configurableBindings в качестве аргументов.
II. Позвонить envs SetMutableBinding конкретный метод, передающий dn, undefined и строгий как аргументы.
Как мы видим в спецификации, аргументы и переменные, объявленные в функции, все фактически определены в среде выполнения, соответствующей функции, в которой они определены. Итак, если аргументы и переменные имеют одинаковое имя, переменная определяется только один раз, а второе объявление игнорируется.