Сегодня мне сказали, что можно вызывать функцию без скобок. Единственное, о чем я мог думать, это использовать такие функции, как apply
или call
.
f.apply(this);
f.call(this);
Но они требуют скобок apply
и call
оставляют нас на первом месте. Я также рассмотрел идею передачи функции некоторому обработчику событий, например setTimeout
:
setTimeout(f, 500);
Но тогда возникает вопрос "как вы вызываете setTimeout
без скобок?"
Так в чем же решение этой загадки? Как вы можете вызвать функцию в Javascript без использования скобок?
javascript
Майк Клак
источник
источник
<insert any solution>
объективно лучше или полезнее, чемf()
.Ответы:
Есть несколько разных способов вызова функции без скобок.
Давайте предположим, что вы определили эту функцию:
Далее следуйте нескольким способам звонка
greet
без скобок:1. Как конструктор
С помощью
new
вы можете вызвать функцию без скобок:Из МДН на
new
оператора :2. Как
toString
илиvalueOf
РеализацияtoString
иvalueOf
являются специальными методами: они вызываются неявно, когда необходимо преобразование:Вы можете (ab) использовать этот шаблон для вызова
greet
без скобок:Или с
valueOf
:valueOf
иtoString
фактически вызываются из метода @@ toPrimitive (начиная с ES6), и поэтому вы также можете реализовать этот метод:2.b Переопределение
valueOf
в прототипе функцииВы можете использовать предыдущую идею, чтобы переопределить
valueOf
метод вFunction
прототипе :Как только вы это сделали, вы можете написать:
И хотя в этой строке присутствуют круглые скобки, фактический вызывающий вызов не имеет круглых скобок. Подробнее об этом читайте в блоге «Вызов методов в JavaScript, без их реального вызова»
3. Как генератор
Вы можете определить функцию генератора (с
*
), которая возвращает итератор . Вы можете вызвать это, используя синтаксис распространения или сfor...of
синтаксисом.Сначала нам нужен генераторный вариант исходной
greet
функции:И затем мы вызываем его без скобок, определяя метод @@ iterator :
Обычно у генераторов где-то есть
yield
ключевое слово, но оно не требуется для вызова функции.Последний оператор вызывает функцию, но это также можно сделать с помощью деструктуризации :
или
for ... of
конструкция, но она имеет свои собственные круглые скобки:Обратите внимание, что вы можете сделать то же самое с исходной
greet
функцией, но это вызовет исключение в процессе после того , какgreet
он был выполнен (протестирован на FF и Chrome). Вы можете управлять исключением с помощьюtry...catch
блока.4. Как добытчик
У @ jehna1 есть полный ответ на этот вопрос, так что отдайте ему должное. Вот способ вызвать функцию без скобок в глобальной области видимости, избегая устаревшего
__defineGetter__
метода. Он используетObject.defineProperty
вместо этого.Для этого нам нужно создать вариант исходной
greet
функции:А потом:
Замените
window
на то, чем является ваш глобальный объект.Вы можете вызвать исходную
greet
функцию, не оставляя следа на глобальном объекте, например так:Но можно утверждать, что у нас есть круглые скобки (хотя они не участвуют в фактическом вызове).
5. Как функция тега
Начиная с ES6, вы можете вызывать функцию, передавая ей литерал шаблона с этим синтаксисом:
Смотрите «Помеченные литералами шаблона» .
6. Как обработчик прокси
Начиная с ES6, вы можете определить прокси :
И тогда чтение любого значения свойства вызовет
greet
:Есть много вариантов этого. Еще один пример:
7. Как экземпляр проверки
instanceof
Оператор выполняет@@hasInstance
метод на второй операнд, когда определяется:источник
valueOf
.func``;
'1' |> alert
Самый простой способ сделать это с
new
оператором:Хотя это неортодоксально и неестественно, это работает и совершенно законно.
new
Оператор не требует скобок , если не используется никаких параметров.источник
!f
приводит к тому же самому без создания экземпляра функции конструктора (которая требует создания нового контекста). Он намного более производительный и используется во многих популярных библиотеках (например, Bootstrap).+
,-
,~
) в таких библиотеках, чтобы сохранить байты в свернутой версии библиотеки , где возвращаемое значение не требуется. (т.е.!function(){}()
) Обычный синтаксис самозвонка(function(){})()
(к сожалению, синтаксисfunction(){}()
не кроссбраузерный) Поскольку самой самозванной функции обычно нечего возвращать, она обычно является целью этого метода сохранения байтовfunction foo() { alert("Foo!") };
Например:!foo
возвращаетfalse
Вы можете использовать геттеры и сеттеры.
Запустите этот скрипт только с:
Редактировать:
Мы можем даже сделать аргументы!
Изменить 2:
Вы также можете определить глобальные функции, которые можно запускать без скобок:
И с аргументами:
Отказ от ответственности:
Как сказал @MonkeyZeus: Никогда не используйте этот кусок кода в производстве, независимо от того, насколько хороши ваши намерения.
источник
__defineGetter__
не рекомендуется. ИспользуйтеObject.defineProperty
вместо этого.Вот пример для конкретной ситуации:
Хотя это утверждение на самом деле не вызывает, но приведет к будущему вызову .
Но я полагаю, что серые области могут подойти для загадок, подобных этой :)
источник
Если мы примем подход латерального мышления, в браузере есть несколько API, которые мы можем использовать для выполнения произвольного JavaScript, включая вызов функции, без каких-либо символов в скобках.
1.
location
иjavascript:
протокол:Одним из таких методов является злоупотребление
javascript:
протоколом оlocation
назначении.Рабочий пример:
Хотя технически
\x28
и\x29
все еще являются круглыми скобками после оценки кода, фактический(
и)
символ не отображаются. Скобки экранируются в строке JavaScript, которая оценивается при назначении.2.
onerror
иeval
:Точно так же, в зависимости от браузера мы можем злоупотреблять глобальным
onerror
, устанавливая егоeval
и выбрасывая что-то, что приведёт к правильному JavaScript. Это хитрее, потому что браузеры не согласуются с таким поведением, но вот пример для Chrome.Рабочий пример для Chrome (не Firefox, другие не тестировались):
Это работает в Chrome, потому
throw'test'
что передается'Uncaught test'
в качестве первого аргументаonerror
, который является почти допустимым JavaScript. Если мы вместо этого сделаемthrow';test'
это пройдет'Uncaught ;test'
. Теперь у нас есть действующий JavaScript! Просто определитеUncaught
и замените тест на полезную нагрузку.В заключение:
Такой код действительно ужасен и никогда не должен использоваться , но иногда используется в атаках XSS, поэтому мораль этой истории заключается в том, чтобы не использовать скобки для предотвращения XSS. Использование CSP для предотвращения такого кода также будет хорошей идеей.
источник
eval
и запись строки без фактического использования символов в скобках.eval
обычно требует скобок, отсюда и взлом уклонения фильтра.\x28
и\x29
до сих пор скобки.'\x28' === '('
,В ES6 у вас есть то, что называется тегами литералов шаблонов .
Например:
источник