Экспериментируя с устаревшим свойством "caller"
, я столкнулся с необычным поведением в браузерах. Были использованы следующие браузеры: Google Chrome 79.0.3945.117
, Firefox 72.0.1
, Edge 44.18362.449.0
Давайте начнем с базового c примера:
function start(){}
start.hasOwnProperty("caller")
Google Chrome: true
, Firefox: false
, Edge: true
Что ж, правда в том, что только в Firefox не используется свое собственное свойство "caller" для каждой объявленной функции.
В таком примере:
function start(){"use strict"};
start.hasOwnProperty("caller")
Google Chrome: false
, Firefox: false
, Edge: false
Давайте посмотрим на следующее код
function a(){b()}
function b(){"use strict";c()}
function c(){console.log(c.caller)}
delete Function.prototype.caller;
a()
А что мы видим? Мы видим, что в Edge возникает только ошибка, и Google Chrome скрывает ее, показывая нам значение null, Firefox возвращает неопределенное значение, поскольку не может найти такое свойство с именем "caller"
где-либо.
Хотя этот случай описывается спецификацией как:
Если реализация расширяет любой функциональный объект собственным свойством с именем "caller", значение этого свойства, как наблюдается с использованием [[Get]] или [ [GetOwnProperty]], не должен быть строгим функциональным объектом. Если это свойство доступа, то функция, которая является значением атрибута свойства [[Get]], никогда не должна возвращать строгую функцию при вызове.
Если мы выполним приведенный выше код, но удалим "use strict"
затем в Google Chrome и Edge мы заметим, что запись console.log (c.caller)
дает нам функцию, которая вызывает текущую функцию, и это, если в Function.prototype
отсутствует свойство "caller"
. Но Firefox в этой ситуации молчит и выдает тот же результат, что и в строгом режиме - "undefined"
.
Кстати, если мы удалим прототипы этих функций, ничего не изменится:
function a(){b()}
function b(){"use strict";c()}
function c(){console.log(c.caller)}
delete Function.prototype.caller;
Object.setPrototypeOf(a,null);
Object.setPrototypeOf(b,null);
Object.setPrototypeOf(c,null);
a();
С Firefox все предельно просто:
- В строгом режиме
- Свойство
"caller"
не определено для функции - При вызове свойства
"caller"
свойство берется из Function.prototype
- При вызове свойства
"caller"
выдается ошибка.
- В обычном режиме
- Свойство
"caller"
не определено для функции - При вызове свойства
"caller"
свойство берется из Function.prototype
- Вызов свойства
"caller"
не выведите ошибку.
Хотя Firefox тоже не так просто. Спецификация гласит следующее: https://tc39.es/ecma262/#sec -адресная функция-свойства . То есть спецификация говорит, что вам нужно определить свойства с ошибками в Function.prototype
при их вызове. Спецификация четко определяет свойство аксессора "caller"
как свойство, которое содержит ошибку. Но Firefox в обычном режиме свойство «вызывающий» кажется переопределенным или изначально определенным для двух типов кода: строгий и не строгий. Является ли это поведение ошибкой Firefox реализации?
Относительно Google Chrome и Edge:
- В строгом режиме
- Свойство
"caller"
не определено для функции - При вызове свойства
"caller"
свойство берется из Function.prototype
- При вызове свойства caller возникает ошибка.
- В обычном режиме
- Свойство
"caller"
определяется для функции - Когда вызывается свойство
"caller"
, свойство не берется из Function.prototype
(где?) - Вызов свойства
"caller"
не приводит к ошибке.
Самым непонятным в этой ситуации является то, как Google Chrome и Edge получают значение для свойства "caller"
с удаленным Function.prototype
(в Function.prototype
есть метод получения и установки свойства "caller"
, а в обычной функции свойство "caller"
не имеет ни метода получения, ни установки)?