Вызов функции без скобок



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



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


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



setTimeout(f, 500);


но тогда возникает вопрос: "как вы вызвать setTimeout без скобок?"



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

501   6  

6 ответов:

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

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

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.б переопределение valueOf функции Прототип

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

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

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

+greet;

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

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

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

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

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

и тогда мы называем его без скобок:

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

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

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

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

или for ... of конструкция:

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

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

4. Как Добытчик

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

нам нужно создать вариант оригинала

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

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

new f;

хотя это неортодоксально и неестественно, это работает и совершенно законно.

The new оператор не требует круглых скобок, если параметры не используются.

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

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

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

h.ello  // Fires up alert "world"

Edit:

мы даже можем сделать аргументы!

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

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

Edit 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: никогда не будет вы используете этот кусок кода в производстве, независимо от того, насколько хороши ваши намерения.

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

window.onload = funcRef;

хотя это утверждение на самом деле не вызов но приведет к будущее вызов.

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

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

1. location и javascript: протокол:

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

Пример:

location='javascript:alert\x281\x29'

хотя технически\x28 и \x29 по-прежнему скобки после того, как код оценивается, фактический ( и ) символ не появляется. Скобки экранируются в строке JavaScript, которая вычисляется при назначении.


2. onerror и eval:

аналогично, в зависимости от браузера, мы можем злоупотреблять глобальными onerror, установив его до eval, и бросая что-то, что будет stringify для допустимого JavaScript. Этот один из них сложнее, потому что браузеры несовместимы в этом поведении, но вот пример для Chrome.

рабочий пример для Chrome (не Firefox, другие непроверенные):

window.onerror=eval;Uncaught=0;throw';alert\x281\x29';

это работает в Chrome, потому что throw'test' пройдет 'Uncaught test' в качестве первого аргумента onerror, что является почти допустимым JavaScript. Если мы вместо throw';test' она пройдет 'Uncaught ;test'. Теперь у нас есть действительный JavaScript! Просто определите Uncaught, и замените тест на полезную нагрузку.


в заключение:

такой код поистине ужасно и никогда не следует использовать, но иногда используется в атаках XSS, поэтому мораль истории заключается в том, чтобы не полагаться на фильтрующую скобку для предотвращения XSS. Используя CSP чтобы предотвратить такой код также было бы хорошей идеей.

в ES6, у вас есть то, что называется Помеченные Литералы Шаблона.

например:

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

foo`Tagged Template Literals`;

Comments

    Ничего не найдено.