Вызов функции без круглых скобок

Мне сказали сегодня, что можно вызвать функцию без круглых скобок. Единственные способы, которыми я мог думать, - использовать функции, такие как apply или call.

f.apply(this);
f.call(this);

Но для этого требуются скобки на apply и call, оставляя нас на квадратной. Я также рассмотрел идею передачи функции в какой-то обработчик событий, например setTimeout:

setTimeout(f, 500);

Но тогда вопрос становится "как вы вызываете setTimeout без круглых скобок?"

Так какое решение этой загадки? Как вы можете вызвать функцию в Javascript без использования круглых скобок?

Ответ 1

Существует несколько способов вызова функции без круглых скобок.

Предположим, что эта функция определена:

function greet() {
    console.log('hello');
}

Затем следуйте некоторым способам вызова greet без круглых скобок:

1. Как конструктор

С помощью new вы можете вызывать функцию без круглых скобок:

new greet; // parentheses are optional in this construct.

Из MDN в new oprator:

Синтаксис

new constructor[([arguments])]

2. Как toString или valueOf Реализация

toString и valueOf являются специальными методы: они вызываются неявно, когда требуется преобразование:

var obj = {
    toString: function() {
         return 'hello';
    }
}

'' + obj; // concatenation forces cast to string and call to toString.

Вы можете (ab) использовать этот шаблон для вызова greet без круглых скобок:

'' + { toString: greet };

Или с помощью valueOf:

+{ valueOf: greet };

2.b Переопределение valueOf в прототипе функции

Вы могли бы взять предыдущую идею, чтобы переопределить метод valueOf в прототипе Function:

Function.prototype.valueOf = function() {
    this.call(this);
    // Optional improvement: avoid `NaN` issues when used in expressions.
    return 0; 
};

Как только вы это сделаете, вы можете написать:

+greet;

И хотя в строке есть круглые скобки, в действительном вызове запуска нет круглых скобок. Подробнее об этом см. В блоге Вызов методов в JavaScript, не называя их действительно

3. Как генератор

Вы можете определить функцию генератора (с *), которая возвращает iterator. Вы можете называть его с помощью синтаксиса или с помощью for...of.

Сначала нам нужен вариант генератора исходной функции greet:

function* greet_gen() {
    console.log('hello');
}

И тогда мы называем это без круглых скобок:

[...{ [Symbol.iterator]: greet_gen }];

Обычно генераторы имеют yield ключевое слово где-то, но оно не нужно для вызова функции.

Последний оператор вызывает функцию, но это также можно сделать с помощью destructuring:

[,] = { [Symbol.iterator]: greet_gen };

или a for ... of:

for ({} of { [Symbol.iterator]: greet_gen });

Обратите внимание, что вы можете сделать выше с помощью оригинальной функции greet, но она вызовет исключение в процессе, после выполнения greet (протестировано в FF и Chrome). Вы можете управлять исключением с блоком try...catch.

4. Как Getter

@jehna1 имеет полный ответ на это, поэтому дайте ему кредит. Вот способ вызова функции круглых скобок - меньше в глобальной области, избегая устаревшего метода __defineGetter__. Вместо этого он использует Object.defineProperty.

Для этого нам нужно создать вариант исходной функции greet:

Object.defineProperty(window, 'greet_get', { get: greet });

И затем:

greet_get;

Замените window любым вашим глобальным объектом.

Вы можете вызвать исходную функцию greet, не оставляя след на глобальном объекте, подобном этому:

Object.defineProperty({}, 'greet', { get: greet }).greet;

Но можно утверждать, что здесь есть круглые скобки (хотя они не участвуют в действительном вызове).

5. В качестве функции тега

С ES6 вы можете вызвать функцию, передав ей литерал шаблона с этим синтаксисом:

greet``;

См. "Tagged Template Literals" . Обычно вы не передавали бы пустой литерал, как здесь, но в качестве примера без круглых звонков он будет делать.

6. Как обработчик прокси-сервера

В ES6 вы можете определить proxy:

var proxy = new Proxy({}, { get: greet } );

И затем, считывая любое значение свойства, вызывается greet:

proxy._; // even if property not defined, it still triggers greet

Есть много вариантов этого. Еще один пример:

var proxy = new Proxy({}, { has: greet } );

1 in proxy; // triggers greet

Ответ 2

Самый простой способ сделать это с помощью оператора new:

function f() {
  alert('hello');
}

new f;

Ответ 3

Вы можете использовать геттеры и сеттеры.

var h = {
  get ello () {
    alert("World");
  }
}

Запустите этот script только с помощью:

h.ello  // Fires up alert "world"

Edit:

Мы можем даже аргументы!

var h = {
  set ello (what) {
    alert("Hello " + what);
  }
}

h.ello = "world" // Fires up alert "Hello world"

Изменить 2:

Вы также можете определить глобальные функции, которые можно запускать без круглых скобок:

window.__defineGetter__("hello", function() { alert("world"); });
hello;  // Fires up alert "world"

И с аргументами:

window.__defineSetter__("hello", function(what) { alert("Hello " + what); });
hello = "world";  // Fires up alert "Hello world"

Отказ от ответственности:

Как @MonkeyZeus заявил: Никогда не используйте этот кусок кода в производстве, независимо от того, насколько хороши ваши намерения.

Ответ 4

Здесь пример для конкретной ситуации:

window.onload = funcRef;

Хотя этот оператор фактически не вызывает, но приведет к будущему вызову.

Но, я считаю, что серые области могут быть в порядке для таких загадок:)

Ответ 5

Если мы примем подход латерального мышления, в браузере есть несколько API, которые мы можем злоупотреблять для выполнения произвольного JavaScript, включая вызов функции, без каких-либо фактических символов скобок.

1. location и javascript::

Одним из таких методов является злоупотребление протоколом javascript: при назначении location.

Рабочий пример:

location='javascript:alert\x281\x29'

Ответ 6

В ES6 у вас есть то, что называется Tagged Template Literals.

Например:

function foo(val) {
    console.log(val);
}

foo`Tagged Template Literals`;