无操作的 JavaScript 约定是什么?

IT技术 javascript function
2021-03-20 12:00:07

无操作的 JavaScript 约定是什么?就像 Pythonpass命令一样。

  • 一种选择只是一个空函数: 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;
6个回答

为了回答最初的问题,纯 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 函数(或相关讨论或谷歌搜索)的各种实现:

AngularJS 1.x中转角2+(似乎不具有本地实现-用自己的如上图所示),灰烬 jQuery的 Lodash的NodeJS Ramda阵营(似乎不具有本地实现-用你自己如上图)、 RxJS下划线

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

@iegik:+1。是的,你是对的。以下所有内容都是等价的: setTimeout(function () {} , 10000); 或 setTimeout(new Function(), 10000);或 setTimeout(Function(), 10000); 或 setTimeout(Function, 10000); 因为 Javascript 语法和 Function 构造函数实现允许这些构造。
2021-04-22 12:00:07
setTimeout(Function(), 10000);
2021-05-02 12:00:07
在 ES6 中或使用 babel 或其他转译器(( )=>{};)技术上纯 JS 并且比它短得多function () {}但完全等效。
2021-05-09 12:00:07
这应该是答案。Function.prototype()如果您不需要超时并希望它立即执行,甚至可以使用
2021-05-13 12:00:07
我有兴趣找到一个类似 no-op 的构造来有效地关闭我程序中的调试代码。在 C/C++ 中,我会使用宏。我测试了将我的 fn 分配给 Function.prototype 并对其计时,将结果与简单地在函数内部使用 if 语句以立即返回进行比较。我还将这些与简单地从循环中完全删除函数的结果进行了比较。不幸的是,Function.prototype 的表现并不好。调用空函数在性能上要好得多,甚至比调用带有简单“if”测试的函数返回还要快。
2021-05-15 12:00:07

最简洁和高性能的 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!`)

我创建了一个 jsPerf 测试来比较一些选项:noop-function似乎在 Firefox 54 中,所有替代方案似乎都差不多;在 Chromium 58 中,Function.prototype速度要慢得多,但其他选项都没有明显的优势。
2021-05-13 12:00:07
@RossAttrill *类似的东西 -_=>{}有一个参数。如果有人使用配置相当严格的 TypeScript,那将无法编译。如果你调用它,你的 IDE 可能会告诉你它接受一个可以是任何类型的参数(JavaScript 尤其是 vscode 中的 TypeScript)。
2021-05-16 12:00:07
_=>{} 少一个字符,做同样的事情。
2021-05-20 12:00:07

无论你在这里想要达到什么目的都是错误的。三元表达式不应用作完整的语句,只能在表达式中使用,因此您的问题的答案是:

没有你的建议,而是做:

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

那么代码就很容易理解、可读并且尽可能高效。

为什么要让它变得更困难,什么时候它可以很简单?

编辑:

那么,“无操作”命令是否基本上表明代码结构较差?

你错过了我的观点。以上都是关于三元表达式的x ? y : z

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

它通常在较低级别的语言(例如汇编或 C)中使用,作为一种使处理器出于计时目的而对一条指令不执行任何操作的方法。

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

如果您使用更复杂的东西,例如$.noop()or var foo = function () {}; foo(),那么解释器可能会执行无用的函数调用,最终会破坏函数堆栈的几个字节和几个周期。

我看到这样的函数$.noop()存在的唯一原因是,仍然能够为某个事件函数提供回调函数,如果它不能调用该回调函数,则会抛出异常。但是,它必然是您需要提供的功能,并且给它noop命名是个好主意,因此您告诉您的读者(可能是 6 个月后的您)您有意提供一个空功能。

归根结底,没有“劣等”或“优越”的代码结构之类的东西。你使用工具的方式要么对要么错。在你的例子中使用三元就像当你想拧螺丝时使用锤子。它会起作用,但您不确定是否可以在那个螺丝上挂一些东西。

可以被视为“较差”或“优越”的是您在代码中放入的算法和想法。但那是另一回事。

@zmo:我确实理解您关于您的评论如何与三元表达式相关的观点;每个人似乎都错过了我的观点,即这只是调用“无操作”功能的一个说明性示例。
2021-04-26 12:00:07
当然,有理由想要/需要无操作功能。不要根据你对某事的 12 秒深入思考做出广泛的概括。JavaScript 是一种使函数作为变量完全可控的语言。假设您需要在没有显式测试的情况下禁用某个功能?这将是完美的。如果您有一个经常出现的函数,例如调试语句,那么最好能够通过将函数重新分配给 no-op 来关闭它,而不必在每次函数出现时添加额外的代码来测试某个变量.
2021-05-10 12:00:07
@bearvarine 感谢您对我的高度评价:-D。您的评论绝对正确,但这并不是真正用于代码设计,只是使用 hack 进行模型设计。您所描述的也称为猴子修补,这是有原因的;-)
2021-05-10 12:00:07
@kmiklas:我不能说我在汇编程序之外找到了对 NOOP 的合法需求。
2021-05-12 12:00:07
那么,“无操作”命令是否基本上表明代码结构较差?
2021-05-17 12:00:07

我认为 jQuerynoop()的主要目的是通过在请求的函数不可用时提供默认函数来防止代码崩溃。例如,考虑以下代码示例,$.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');

最后回答你的问题,我想“传统的无操作”是从未写过的。

但是有时您必须提供一个函数。例如,使用 promise then(fn, fn) 有时您想提供第二个函数而不是第一个函数。因此你需要一些东西作为占位符......mypromise.then($.noop, myErrorhandler);
2021-05-18 12:00:07

使用Function.prototypeover绝对没有问题或性能损失() => {}

主要好处Function.prototype是拥有一个单例函数,而不是每次都重新定义一个新的匿名函数。Function.prototype在定义默认值和记忆时使用 no-op 尤为重要,因为它为您提供了一个永远不会改变的一致对象指针。

我推荐Function.prototype而不是Function因为它们不一样的原因:

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

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

此外,来自其他答案的基准具有误导性实际上,Function.prototype执行速度比() => {}取决于您编写和运行基准测试的方式要

你不能相信 JS 基准测试<< 特别在这个问题上调用基准。

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