没有操作的JavaScript约定是什么?


121

没有操作的JavaScript约定是什么?就像Python pass命令一样。

  • 一个选择就是一个空函数: function() {}
  • jQuery提供了$.noop(),它只是调用了上面的empty函数。
  • 只需输入值falseor 可以接受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 2014年

11
这些替代0方法实际上都没有更好(或更糟)的选择。我想说的是,正确的做法是在没有意义的情况下if (a === 1) doSomething();不使用? :
Pointy 2014年

6
您正在滥用三元运算符,但会产生副作用。如果有必要,请if (statement) action; else ;
mplungjan

false0将会起作用;null是表达无操作的好方法。
马特

3
我希望三元有某种必要,由于某种原因我们看不到……非常像您使代码变得很酷(我们都完成了!)
Stachu 2014年

Answers:


95

为了回答最初的问题,纯Javascript中Noop函数的最优雅,最整洁的实现(也将在此处进行讨论)是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(从而节省了CPU周期),但可能存在与此相关的性能问题(其他人在评论中或在其他答案)。

但是,可以这么说,您可以轻松定义自己的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中转角2+(似乎不具有本地实现-用自己的如上图所示),灰烬 jQuery的 Lodash的NodeJS Ramda阵营(似乎不具有本地实现-用你自己如上所示), RxJS下划线

底线:尽管Function.prototype是用Java语言表达noop的一种优雅方式,但是,可能存在一些与其使用有关的性能问题。因此,您可以定义和使用自己的代码(如上所示),也可以使用您可能在代码中使用的库/框架定义的代码。


5
这应该是答案。Function.prototype()如果您不需要超时并希望立即执行,甚至可以使用。
弹簧

1
setTimeout(Function(), 10000);
iegik

@iegik:+1。是的,你是对的。以下所有都是等效的:setTimeout(function(){},10000); 或setTimeout(new Function(),10000);或setTimeout(Function(),10000); 或setTimeout(Function,10000); 因为Javascript语法和Function构造函数实现允许这些构造。
艾伦CS

5
在ES6中,或者使用babel或其他Transpiler,从(( )=>{};)技术上讲,它是Pure JS,并且比function () {}完全短而短得多。
雷·福斯

2
我有兴趣寻找一种类似于no-op的结构来有效关闭程序中的调试代码。在C / C ++中,我会使用宏。我测试了将fn分配给Function.prototype并对其计时,将结果与在函数内部简单地包含if语句以立即返回进行比较。我还将这些与仅从循环中完全删除该函数的结果进行了比较。不幸的是,Function.prototype的表现根本不佳。调用一个空函数在性能上要好得多,甚至比使用内部简单的“ if”测试返回该函数更快。
bearvarine

72

最简洁和性能最强的noop是一个空的箭头功能()=>{}

箭头功能可以在除IE之外的所有浏览器中正常运行(如果需要,可以进行babel转换): MDN


()=>{}Function.Prototype

  • ()=>{}更快的87%Function.prototype在铬67。
  • ()=>{}快25%,Function.prototype在Firefox 60。
  • ()=>{}更快的85%Function.prototype在边缘(2018年6月15日)
  • ()=>{}代码少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速度要慢得多,但其他任何选择都没有明显的优势。
卢卡斯·韦尔克梅斯特

_=>{}少一个字符,做同样的事情。
Ross Attrill

@RossAttrill *类似的东西- _=>{}有一个参数。如果有人使用具有相当严格配置的TypeScript,则无法编译。如果调用它,您的IDE可能会告诉您它接受一个可以是任何类型的参数(包括JavaScript,尤其是vscode中的TypeScript)。
cchamberlain

15

无论您倾向于在这里实现什么,都是错误的。三元表达式不能仅在表达式中用作完整语句,因此您的问题的答案是:

没有您的建议,而是:

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

那么这些代码就易于理解,可读且尽可能高效。

当它可以变得简单时,为什么要使其更加困难?

编辑:

那么,“ no-operation”命令是否基本上表示劣质的代码结构?

你想念我的意思。以上所有都是关于三元表达式的x ? y : z

但是,无操作命令在高级语言(如Javascript)中没有意义。

它通常以较低级别的语言(例如汇编语言或C语言)使用,以使处理器对一条指令不执行任何操作以达到定时目的。

在JS,无论你做0;null;function () {};或空语句,有很大的机会,它会被解释器时,它读取它忽略,但之前它被解释,所以到最后,你只会让你的程序是在非常短的时间内加载速度会变慢。Nota Bene:我以为是这样,因为我没有参与任何广泛使用的JS解释器,每个解释器都有可能有自己的策略。

万一您使用了诸如$.noop()或之类的更复杂的东西var foo = function () {}; foo(),则解释器可能会执行无用的函数调用,最终会破坏函数堆栈的几个字节和几个周期。

我看到这样的函数$.noop()存在的唯一原因是仍然能够将某个回调函数提供给某个事件函数,如果该事件函数无法调用该回调,则该事件函数将引发异常。但是,那一定是您需要赋予的功能,并且给它noop起个名字是个好主意,因此您是在告诉读者(可能在6个月内可能是您),您故意赋予了一个空的功能。

最后,没有“劣等”或“优等”的代码结构。您使用工具的方式是对还是错。.例如,使用三元结构就像想拧螺丝时使用锤子。可以,但是您不确定是否可以在该螺钉上挂东西。

可以认为是“劣等”或“优等”的是您在代码中放入的算法和思想。但这是另一回事。


1
那么,“ no-operation”命令是否基本上表示劣质的代码结构?
kmiklas 2014年

3
@kmiklas:我不能说我曾经在汇编程序之外找到合法的NOOP需求。
马特·伯兰德

@zmo:我确实理解您的观点,即您的评论与三元表达有何关系;每个人似乎都错失了我的观点,即这仅仅是调用“无操作”功能的一个示例。
kmiklas 2014年

1
当然,有理由想要/需要无操作功能。不要根据您12秒钟对某件事的深入思考做出广泛的概括。JavaScript是一种使函数作为变量完全可控的语言。假设您需要在没有显式测试的情况下禁用某个功能?这将是完美的。如果您有一个经常出现的功能(例如调试语句),那么可以通过将功能重新分配为no-op来关闭它,而不是每次该功能出现时都必须添加额外的代码来测试某些变量,这样会很好。
bearvarine '16

2
@bearvarine谢谢您对我的高度评价:-D。您的评论绝对正确,但这并不是真正的代码设计,只是使用黑客的模型设计。您描述的内容也称为“猴子修补”,这是有原因的;-)
zmo

7

我认为jQuery noop()主要用于通过在请求的功能不可用时提供默认功能来防止代码崩溃。例如,考虑以下代码示例,$.noop如果fakeFunction未定义,则选择,以防止下一个调用fn崩溃:

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

然后,noop()通过避免在代码的任何地方多次编写相同的空函数来节省内存。顺便说一句,$.noopfunction(){}(每个令牌节省6个字节)短一点。因此,您的代码与空函数模式之间没有任何关系。使用nullfalse或者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
但是有时您必须提供一个功能。例如,使用promise then(fn,fn)有时您想提供第二个功能,而不是第一个功能。因此,您需要mypromise.then($.noop, myErrorhandler);
预留

3

我用:

 (0); // nop

测试此运行的执行时间为:

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

结果:标记:0.000ms

Boolean( 10 > 9)可以将使用简化为( 10 > 9)返回哪个true。想到使用我完全期望的单个操作数的想法(0);会返回false,但它只是返回参数,可以通过在控制台上执行此测试来检查该参数。

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

1
许多尝试这样做的人将会得到argument 0 is not a function
Code Whisperer'7

4
您只需分配0。IMO noop应该是一个以undefined结果求值的函数。
cchamberlain

1
这个说法怎么样(0); 分配0?,var和等号在哪里?(0)前面没有函数名称,所以我看不出它怎么可能是参数?如果您尝试typeof((0)),它会以数字形式返回。当我回答问题时,我提供了一个模仿NOP的声明,但我愿意将答案更改为简单使用; 代表一个空声明
Eggs

1
我认为(0); 是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基准测试 << <<特别提到了这个问题的基准测试。

不要根据基准设置代码样式;做任何可维护的事情,让解释器弄清楚从长远来看如何进行优化。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.