Каковы правила JavaScript для отсутствия операций?


121

Каковы правила JavaScript для отсутствия операций? Как passкоманда Python .

  • Один из вариантов - это просто пустая функция: function() {}
  • предлагает jQuery $.noop(), который просто вызывает указанную выше пустую функцию.
  • Допустимо ли просто ввести значение falseили 0?

В контексте ... все это работает без ошибок в Chrome:

var a = 2;
(a === 1) ? alert(1) : function() {};
(a === 1) ? alert(1) : $.noop();
(a === 1) ? alert(1) : false;
(a === 1) ? alert(1) : 0;

РЕДАКТИРОВАТЬ: Многие люди ответили: «Не делайте этого! Измените структуру кода!» Это напоминает мне сообщение, в котором кто-то спросил, как обнюхать браузер. Он получил массу сообщений, в которых говорилось: «НЕ ДЕЛАЙТЕ ЭТО! ЭТО ЗЛО», но никто не объяснил ему, как обнюхивать браузер . Это не обзор кода. Представьте, что вы имеете дело с устаревшим кодом, который нельзя изменить, и без передачи какой-либо функции он выдаст ошибку. Или, попросту, заказчик так хочет и платит мне . Итак, с уважением, ответьте на вопрос : как лучше всего указать в JavaScript функцию «без операции»?

EDIT2: Как насчет одного из них?

true;
false;
0;
1;
null;

7
Почему не простое выражение if?
epascarello 07

11
Ни одна из этих альтернатив 0фактически не лучше (или хуже). Я бы сказал, что правильно - это if (a === 1) doSomething();не использовать, ? :когда это не имеет смысла.
Pointy

6
Вы злоупотребляете тернарным оператором с побочным эффектом. Если нужно, сделайтеif (statement) action; else ;
mplungjan

Да falseили 0будет работать; nullэто хороший способ выразить отсутствие работы.
Мэтт

3
Я надеюсь, что у троичного есть какая-то необходимость, которую мы не видим по какой-то причине ... Очень похоже, что вы усложняете свой код, чтобы чувствовать себя круто (мы все это сделали!)
Стаху

Ответы:


95

Чтобы ответить на исходный вопрос, самой элегантной и изящной реализацией функции noop в чистом Javascript (что также обсуждается здесь ) является Function.prototype . Это потому что:

  1. Function.prototype - это функция:

typeof Function.prototype === "function" // returns true

  1. Он может быть вызван как функция и по сути ничего не делает, как показано здесь:
setTimeout(function() {
      console.log('Start: ', Date.now());
      Function.prototype();
      console.log('End  : ', Date.now());
    }, 1000);

Хотя это "истинный noop", поскольку большинство браузеров, похоже, ничего не делают для выполнения noop, определенного таким образом (и, следовательно, для экономии циклов процессора), могут быть некоторые проблемы с производительностью, связанные с этим (как также упоминалось другими в комментариях или в другие ответы).

Однако, как уже было сказано, вы можете легко определить свою собственную функцию noop, и, фактически, многие библиотеки и фреймворки также предоставляют функции noop. Вот несколько примеров:

var noop = function () {};           // Define your own noop in ES3 or ES5
const noop = () => {};               // Define in ES6 as Lambda (arrow function)
setTimeout(noop, 10000);             // Using the predefined noop

setTimeout(function () {} , 10000);  // Using directly in ES3 or ES5
setTimeout(() => {} , 10000);        // Using directly in ES6 as Lambda (arrow function)

setTimeout(angular.noop, 10000);     // Using with AngularJS 1.x
setTimeout(jQuery.noop, 10000);      // Using with jQuery

Вот алфавитный список различных реализаций функций noop (или связанных обсуждений или поиска в Google):

AngularJS 1.x , Angular 2+ (похоже, не имеет собственной реализации - используйте свою, как показано выше), Ember , jQuery , Lodash , NodeJS , Ramda , React (похоже, не имеет собственной реализации - используйте свою собственную как показано выше), RxJS , Underscore

ИТОГ : Хотя Function.prototype - это элегантный способ выразить сообщение в Javascript, тем не менее, могут возникнуть некоторые проблемы с производительностью, связанные с его использованием. Итак, вы можете определить и использовать свой собственный (как показано выше) или использовать тот, который определен библиотекой / фреймворком, который вы можете использовать в своем коде.


5
Это должен быть ответ. Можно даже использовать, Function.prototype()если вам не нужен тайм-аут и вы хотите, чтобы он выполнялся сразу.
загружено

1
setTimeout(Function(), 10000);
iegik

@iegik: +1. Да вы правы. Все следующие элементы эквивалентны: setTimeout (function () {}, 10000); ИЛИ setTimeout (новая функция (), 10000); ИЛИ setTimeout (Функция (), 10000); ИЛИ setTimeout (Функция, 10000); поскольку грамматика Javascript и реализация конструктора функций допускают эти конструкции.
Alan CS

5
В ES6 или с использованием babel или другого транспилятора (( )=>{};)технически чистый JS и намного короче, function () {}но точно эквивалентен.
Ray Foss

2
Мне было интересно найти конструкцию без операций, которая могла бы эффективно отключить отладочный код в моей программе. В C / C ++ я бы использовал макросы. Я протестировал присвоение моей fn функции Function.prototype и рассчитал время, сравнивая результаты с простым наличием оператора if внутри функции для немедленного возврата. Я также сравнил их с результатами простого удаления функции из цикла. К сожалению, Function.prototype совсем не работал. вызов пустой функции был намного лучше по производительности, даже быстрее, чем вызов функции с помощью простого теста if внутри для возврата.
Bearvarine 08

73

Наиболее краткая и производительный Noop является пустой функцией стрелка : ()=>{}.

Стрелочные функции изначально работают во всех браузерах, кроме IE (при необходимости есть преобразование babel ): MDN


()=>{} против Function.Prototype

  • ()=>{}на 87% быстрее, чем Function.prototypeв Chrome 67.
  • ()=>{}на 25% быстрее, чем Function.prototypeв Firefox 60.
  • ()=>{}на 85% быстрее, чем Function.prototypeв Edge (15.06.2018) .
  • ()=>{}на 65% меньше кода, чем Function.prototype.

В приведенном ниже тесте используется функция стрелки для смещения Function.prototype, но функция стрелки является явным победителем:

const noop = ()=>{};
const noopProto = Function.prototype;

function test (_noop, iterations) {
    const before = performance.now();
    for(let i = 0; i < iterations; i++) _noop();
    const after = performance.now();
    const elapsed = after - before;
    console.info(`${elapsed.toFixed(4)}MS\t${_noop.toString().replace('\n', '')}\tISNOOP? ${_noop() === undefined}`);
    return elapsed;
}

const iterations = 10000000
console.info(`noop time for ${iterations.toLocaleString()} iterations`)
const timings = {
    noop: test(noop, iterations),
    noopProto: test(noopProto, iterations)
}

const percentFaster = ((timings.noopProto - timings.noop)/timings.noopProto).toLocaleString("en-us", { style: "percent" });
console.info(`()=>{} is ${percentFaster} faster than Function.prototype in the current browser!`)


1
Я создал тест jsPerf, чтобы сравнить некоторые варианты: noop-function . Похоже, что в Firefox 54 все альтернативы примерно эквивалентны; в Chromium 58 он Function.prototypeработает значительно медленнее, но ни один из других вариантов не имеет явного преимущества.
Lucas

_=>{}на один символ меньше и делает то же самое.
Росс Аттрилл,

@RossAttrill * похожая штука - _=>{}имеет единственный параметр. Если кто-то использует TypeScript с достаточно строгой конфигурацией, он не будет компилироваться. Если вы его вызовете, ваша IDE, скорее всего, сообщит вам, что принимает один параметр, который может быть любого типа (как JavaScript, так и особенно TypeScript в vscode).
cchamberlain

15

все, чего вы здесь добиваетесь, неправильно. Тернарные выражения не должны использоваться в качестве полного оператора, только в выражении, поэтому ответ на ваш вопрос:

ни одно из ваших предложений, вместо этого сделайте:

var a = 2;
if (a === 1)
    alert(1)
// else do nothing!

тогда код будет легко понятным, читаемым и настолько эффективным, насколько это возможно.

Зачем усложнять, если можно просто?

редактировать:

Итак, означает ли команда «без операции» в основном плохую структуру кода?

Вы упускаете мою точку зрения. Все вышесказанное касается троичного выражения x ? y : z.

Но команда без операции не имеет смысла в языках более высокого уровня, таких как Javascript.

Обычно он используется на языках более низкого уровня, таких как ассемблер или C, как способ заставить процессор ничего не делать для одной инструкции для целей синхронизации.

В JS, делаете ли вы 0;, null;, function () {};или пустое выражение, есть большие шансы , что он будет игнорироваться интерпретатором , когда он читает, но прежде , чем она будет интерпретироваться, так что в конце концов, вы просто сделать вашу программа будет загружается медленнее на очень крошечный промежуток времени. Nota Bene : я предполагаю это, поскольку я не участвую в широко используемых интерпретаторах JS, и есть вероятность, что у каждого интерпретатора есть своя собственная стратегия.

Если вы используете что-то более сложное, например $.noop()или var foo = function () {}; foo(), тогда интерпретатор может выполнить бесполезный вызов функции, который в конечном итоге испортит несколько байтов вашего стека функций и несколько циклов.

Единственная причина, по которой я вижу такую ​​функцию, $.noop()которая могла бы существовать, - это возможность по-прежнему передавать функцию обратного вызова некоторой функции события, которая генерирует исключение, если не может вызвать этот обратный вызов. Но тогда вам обязательно нужно передать эту функцию, и дать ей noopимя - хорошая идея, поэтому вы говорите своим читателям (и это может быть вы через 6 месяцев), что вы намеренно даете пустую функцию.

В конце концов, не существует таких понятий, как «низшая» или «высшая» структура кода. Вы либо правы, либо ошибаетесь в том, как вы используете свои инструменты. Использование троичного для вашего примера похоже на использование молотка, когда вы хотите завинтить. Это сработает, но вы не уверены, что сможете что-нибудь повесить на этот винт.

То, что можно считать «низшим» или «превосходным», - это алгоритм и идеи, которые вы вкладываете в свой код. Но это другое дело.


1
Итак, означает ли команда «без операции» в основном плохую структуру кода?
kmiklas 07

3
@kmiklas: Я не могу сказать, что когда-либо обнаруживал законную потребность в NOOP, помимо ассемблера.
Мэтт Берланд

@zmo: Я понимаю вашу точку зрения относительно того, как ваши комментарии относятся к тернарному выражению; Кажется, все упустили мою мысль о том, что это был просто иллюстративный пример вызова функции «Нет операции».
kmiklas 07

1
Конечно, есть причины хотеть / нуждаться в безоперационной функции. Не делайте широких обобщений, основываясь на ваших 12-секундных глубоких размышлениях о чем-либо. JavaScript - это язык, который делает функции полностью управляемыми как переменные. Предположим, вам нужно отключить функцию без явного тестирования? Это было бы идеально для этого. Если у вас есть функция, которая часто появляется, например, оператор отладки, было бы неплохо иметь возможность отключить ее, переназначив функцию на no-op, вместо того, чтобы добавлять дополнительный код для проверки некоторой переменной каждый раз, когда функция появляется ,
Bearvarine 07

2
@bearvarine, спасибо за высокое мнение обо мне :-D. Вы абсолютно правы в своем комментарии, но это не совсем для дизайна кода, просто дизайн макета с использованием хака. То, что вы описываете, также называется исправлением обезьяны, и для этого есть причина ;-)
zmo

7

Я думаю, что jQuery noop()в основном предназначен для предотвращения сбоев кода, предоставляя функцию по умолчанию, когда запрошенная недоступна. Например, учитывая следующий пример кода, $.noopвыбирается, если fakeFunctionне определено, что предотвращает fnсбой следующего вызова :

var fn = fakeFunction || $.noop;
fn() // no crash

Затем noop()позволяет экономить память, избегая многократного написания одной и той же пустой функции повсюду в вашем коде. Кстати, $.noopэто немного короче function(){}(6 байтов на токен). Итак, нет никакой связи между вашим кодом и шаблоном пустой функции. Используйте null, falseили 0если хотите, в вашем случае побочных эффектов не будет. Кроме того, стоит отметить, что этот код ...

true/false ? alert('boo') : function(){};

... совершенно бесполезно, так как вы никогда не вызовете функцию, а эта ...

true/false ? alert('boo') : $.noop();

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

true/false ? alert('boo') : undefined;

Давайте заменим тернарное выражение на ifоператор, чтобы увидеть, насколько оно бесполезно:

if (true/false) {
    alert('boo');
} else {
    $.noop(); // returns undefined which goes nowhere
}

Вы можете просто написать:

if (true/false) alert('boo');

Или даже короче:

true/false && alert('boo');

Чтобы наконец ответить на ваш вопрос, я предполагаю, что «обычная операция без операции» - это та, которая никогда не записывается.


1
Однако иногда вам нужно предоставить функцию. Например, с помощью promises then (fn, fn) иногда нужно предоставить вторую функцию, но не первую. следовательно, вам нужно что-то для заполнителя ...mypromise.then($.noop, myErrorhandler);
Джон Хенкель

3

Я использую:

 (0); // nop

Чтобы проверить время выполнения этого запуска как:

console.time("mark");
(0); // nop
console.timeEnd("mark");

результат: оценка: 0,000 мс

Использование Boolean( 10 > 9)может быть сведено к простому ( 10 > 9)возвращению true. Придумывая идею использовать один операнд, я полностью ожидал, (0);что он вернется false, но он просто возвращает аргумент, который можно просмотреть, выполнив этот тест на консоли.

> var a = (0);
< undefined
> a
< 0

1
многие, кто попытается это сделать, получатargument 0 is not a function
Code Whisperer

4
Вы просто присваиваете 0. IMO noopдолжна быть функцией, которая оценивает undefinedрезультат.
cchamberlain

1
Как это заявление (0); присваивая 0 ?, где var и знак равенства? Перед (0) нет имени функции, поэтому я не понимаю, как это могло быть аргументом? если вы попробуете typeof ((0)), он вернется как число. Когда я отвечаю на вопрос, я предоставляю утверждение, которое я использую для имитации NOP, но я готов изменить свой ответ на простое использование; для представления пустого утверждения
Eggs

1
Я думаю (0); приемлемое решение вопроса OP. Я думаю, что люди запутались, потому что они нашли эту страницу, когда искали функцию, которая ничего не делает, а не инструкцию, которая ничего не делает. OP не помогает, изначально предлагая function(){}решение. Вызов (0)()вызоветTypeError: 0 is not a function
Бенджамин

Я имел в виду var a = (0);. Отсутствие операции не должно изменять память, и ваш пример присваивания делает именно это. Сам (0)по себе может считаться бесполезным бездействием (в JavaScript их бесконечное количество, поэтому нет ничего, что делало бы ваш пример здесь особенным).
cchamberlain

2

Нет абсолютно никаких проблем или снижения производительности при использовании Function.prototypeover () => {}.

Основное преимущество Function.prototype- наличие одноэлементной функции вместо того, чтобы каждый раз заново определять новую анонимную функцию. Особенно важно использовать Function.prototypeзапретные действия, например, при определении значений по умолчанию и запоминании, поскольку это дает вам согласованный указатель на объект, который никогда не изменяется.

Причина, по которой я рекомендую, Function.prototypeа не Functionпотому, что они не совпадают:

Function() === Function()
// false

Function.prototype() === Function.prototype()
// true

Кроме того, тесты из других ответов вводят в заблуждение . Фактически, Function.prototypeработает быстрее, чем () => {}зависит от того, как вы пишете и запускаете тест:

Вы не можете доверять тестам JS << Конкретно вызываем тесты по этому вопросу.

Не стилизуйте свой код на основе тестов; делайте все, что можно поддерживать, и позвольте интерпретатору понять, как оптимизировать в конечном итоге.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.