简体   繁体   English

为什么Airbnb风格指南表示不鼓励依赖功能名称推断?

[英]Why does the Airbnb style guide say that relying on function name inference is discouraged?

// bad
class Listing extends React.Component {
  render() {
    return <div>{this.props.hello}</div>;
  }
}

// bad (relying on function name inference is discouraged)
const Listing = ({ hello }) => (
  <div>{hello}</div>
);

// good
function Listing({ hello }) {
  return <div>{hello}</div>;
}

This is taken from the Airbnb react style guide. 这取自Airbnb反应风格指南。 Can someone please explain why "relying on function name inference is discouraged"? 有人可以解释为什么“不鼓励依赖功能名称推断”? Is it just a style concern? 这只是一种风格问题吗?

I think this could also have something to do with the unexpected behaviour that you might run into from implicitly giving a lexical name to what you may expect to be an anonymous function. 我认为这也可能与您可能遇到的意外行为有关,这些行为可能会隐含地将词汇名称赋予您可能期望的匿名函数。

Say for example someone understood the arrow function: 例如,有人理解箭头功能:

(x) => x+2;

To have the regular function equivalent: 要使常规函数等效:

function(x) {
  return x+2;
}

It would be pretty easy to expect this code: 期望这段代码很容易:

let foo = (x) => x+2;

To then be the equivalent of: 那么相当于:

let foo = function(x) {
  return x+2;
}

Where the function remains anonymous and would be incapable of referencing itself to do things like recursion. 函数仍然是匿名的,并且无法引用自身来执行递归等操作。

So if then, in our blissful ignorance, we had something like this happening: 所以如果那时候,在我们幸福的无知中,我们发生了类似的事情:

let foo = (x) => (x<2) ? foo(2) : "foo(1)? I should be a reference error";
console.log(foo(1));

It would successfully run because that function obviously wasn't anonymous: 它会成功运行,因为该功能显然不是匿名的:

let foo = function foo(x) {
  return (x<2) ? foo(2) : "foo(1)? I should be a reference error";
}  

This could potentially be exacerbated by the fact that in other situations where Babel implicitly adds a name to anonymous functions, (which I think is actually a bit of a side-effect of supporting implicit function names in the first place, though I could be wrong on that), they correctly handle any edge cases and throw reference errors where you would expect. 在Babel隐式地为匿名函数添加名称的其他情况下,这可能会加剧这种情况(我认为这实际上是支持隐式函数名称的副作用,但我可能是错的在那个),他们正确处理任何边缘情况并抛出你期望的参考错误。

For example: 例如:

let foo = {
  bar: function() {}
} 

// Will surprisingly transpile to..

var foo = {
  bar: function bar() {}
}; 


// But doing something like:

var foo = {
  bar: function(x) {
    return (x<2) ? bar(2) : 'Whats happening!?';
  }
}

console.log(foo.bar(1));

// Will correctly cause a ReferenceError: bar is not defined

You can check 'view compiled' on this quick DEMO to see how Babel is actually transpiling that to maintain the behaviour of an anonymous function. 您可以在这个快速演示中查看“查看已编译”以查看Babel实际上是如何进行转换以维护匿名函数的行为。


In short, being explicit with what you are doing is typically a good idea because you know exactly what to expect from your code. 简而言之,明确你正在做的事情通常是一个好主意,因为你确切地知道你的代码会有什么期望。 Discouraging the use of implicit function naming is likely a stylistic choice in support of this while also remaining concise and straightforward. 不鼓励使用隐式函数命名可能是支持这一点的风格选择,同时也保持简洁明了。

And probably hoisting. 可能还在吊装。 But hey, fun side trip. 但是,嘿,有趣的一趟。

EDIT #2: Found AirBnbs reason in their Javascript style guide 编辑#2:在他们的Javascript风格指南中找到了AirBnbs的原因

Don't forget to name the expression - anonymous functions can make it harder to locate the problem in an Error's call stack ( Discussion ) 不要忘记命名表达式 - 匿名函数可以使错误调用堆栈中的问题更难找到( 讨论

Original answer below 原答案如下

MDN has a good run-down on how function name inference works, including two warnings: MDN对函数名称推断的工作方式有很好的规定,包括两个警告:

Observations 意见

There is non-standard <function>.name inference behaviour in the following two scenarios: 在以下两种情况中存在非标准的<function>.name推断行为:

  1. when using script interpreters 使用脚本解释器时

The script interpreter will set a function's name property only if a function does not have an own property called name... 仅当函数没有名为name的自己的属性时,脚本解释器才会设置函数的name属性。

  1. when using js tooling 使用js工具时

Be careful when using Function.name and source code transformations such as those carried out by JavaScript compressors (minifiers) or obfuscators 使用Function.name和源代码转换时要小心,例如JavaScript压缩器(缩小器)或混淆器执行的转换

.... ....

In the uncompressed version the program runs into the truthy-branch and logs 'foo' is an instance of 'Foo' whereas in the compressed version it behaves differently and runs into the else-branch. 在未压缩的版本中,程序运行到truthy-branch并且日志'foo'是'Foo'的实例,而在压缩版本中它的行为不同并且运行到else-branch。 Therefore, if you rely on Function.name like in the example above, make sure your build pipeline doesn't change function names or don't assume a function to have a particular name. 因此,如果您依赖于上面示例中的Function.name,请确保您的构建管道不会更改函数名称或不假定函数具有特定名称。

What is function name inference? 什么是函数名称推断?

The name property returns the name of a function, or (before ES6 implementations) an empty string for anonymous functions name属性返回函数的名称,或者(在ES6实现之前)返回匿名函数的空字符串

function doSomething() {}

console.log(doSomething.name); // logs "doSomething"

Functions created with the syntax new Function(...) or just Function(...) have their name property set to an empty string. 使用语法new Function(...)或只是Function(...)创建的函数将其name属性设置为空字符串。 In the following examples anonymous functions are created, so name returns an empty string 在以下示例中,将创建匿名函数,因此name返回一个空字符串

var f = function() {};
var object = {
  someMethod: function() {}
};

console.log(f.name == ''); // true
console.log(object.someMethod.name == ''); // also true

Browsers that implement ES6 functions can infer the name of an anonymous function from its syntactic position . 实现ES6函数的浏览器可以从其语法位置推断出匿名函数的名称 For example: 例如:

var f = function() {};
console.log(f.name); // "f"

Opinion 意见

Personally I prefer (arrow) functions assigned to a variable for three basic reasons: 我个人更喜欢(箭头)函数分配给变量有三个基本原因:

Firstly, I don't ever use function.name 首先,我从来没有使用function.name

Secondly, mixing lexical scope of named functions with assignment feels a little loose: 其次,将命名函数的词法范围与赋值混合感觉有点宽松:

// This...
function Blah() {
   //...
}
Blah.propTypes = {
 thing: PropTypes.string
}
// ...is the same as...
Blah.propTypes = {
 thing: PropTypes.string
}
function Blah() {
   //...
}

// ALTERNATIVELY, here lexical-order is enforced
const Blah = () => {
   //...
}
Blah.propTypes = {
    thing: PropTypes.string
}

And thirdly, all things being equal, I prefer arrow functions: 第三,在所有条件相同的情况下,我更喜欢箭头功能:

  • communicate to reader that there is no this , no arguments etc 告诉读者没有this ,没有arguments
  • looks better (imho) 看起来更好(imho)
  • performance (last time I looked, arrow functions were marginally faster) 性能(我上次看,箭头功能略快)

EDIT: Memory snapshots 编辑:内存快照

I was listening to a Podcast and guest told of a situation were he had to deal with the limitations of using arrow functions with memory profiling, I have been in the exact same situation before. 我正在收听一个播客 ,客人告诉他一个情况是他必须处理使用箭头功能和内存分析的限制,我之前一直处于完全相同的情况。

Currently, memory snapshots will not include a variable name - so you might find yourself converting arrow functions to named functions just to hook up the memory profiler. 目前,内存快照不包含变量名称 - 因此您可能会发现自己将箭头函数转换为命名函数只是为了连接内存分析器。 My experience was quite straightforward, and I'm still happy with arrow functions. 我的经历非常简单,我对箭头功能感到满意。

Plus I've only used memory snapshots once, so I feel comfortable forgoing some "instrumention" for (subjective) clarity by default. 另外,我只使用了一次内存快照,因此我觉得在默认情况下(主观)清晰度可以放弃一些“指示”。

This is because: 这是因为:

const Listing = ({ hello }) => (
  <div>{hello}</div>
);

has an inferred name of Listing, while it looks like you are naming it, you actually aren't: 有一个推断的列表名称,虽然它看起来像你命名它,你实际上不是:

Example

// we know the first three ways already...

let func1 = function () {};
console.log(func1.name); // func1

const func2 = function () {};
console.log(func2.name); // func2

var func3 = function () {};
console.log(func3.name); // func3

what about this? 那这个呢?

const bar = function baz() {
    console.log(bar.name); // baz
    console.log(baz.name); // baz
};

function qux() {
  console.log(qux.name); // qux
}

As any other style guide, Airbnb's is opinionated and isn't always well reasoned. 与任何其他风格指南一样,Airbnb是自以为是,并不总是很有道理。

Function name property isn't supposed to be used for anything but debugging in client-side application because function original name is lost during minification. 函数name属性不应该用于客户端应用程序中的任何调试,因为函数原始名称在缩小期间会丢失。 As for debugging, it becomes less efficient if a function doesn't have a meaningful name in call stack, so it's beneficial to preserve it in some cases. 至于调试,如果函数在调用堆栈中没有有意义的名称,则效率会降低,因此在某些情况下保留它是有益的。

A function gets name with both function definition like function Foo = () => {} and function named expression like an arrow in const Foo = () => {} . 函数获取name ,其函数定义类似function Foo = () => {} ,函数名称表达式类似于const Foo = () => {}的箭头。 This it results in Foo function having a given name, Foo.name === 'Foo' . 这导致Foo函数具有给定名称, Foo.name === 'Foo'

Some transpilers follow the specification. 一些转发器遵循规范。 Babel transpiles this code to ES5: Babel将此代码转换为ES5:

var Foo = function Foo() {};

And TypeScript breaks the specification: TypeScript打破了规范:

var Foo = function () {};

This doesn't mean that named function expression is bad and should be discouraged. 这并不意味着命名函数表达式是坏的,应该不鼓励。 As long as a transpiler is spec-compliant or function name doesn't matter, this concern can be discarded. 只要转换器符合规范或功能名称无关紧要,就可以放弃这种担忧。

The problem is applicable to transpiled applications. 该问题适用于转换后的应用程序。 It depends on a transpiler in use and a necessity to keep function name property. 它取决于使用中的转换器以及保持函数name属性的必要性。 The problem doesn't exist in native ES6. 本机ES6中不存在此问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 带有 Airbnb 风格指南的 ESLint 不适用于所有规则 - ESLint with Airbnb style guide does not work for all rules Airbnb样式指南:命名约定的规则不起作用 - Airbnb style guide:rules for naming conventions not working 为什么即使我将其设置为两个空格和硬制表符,Eslint 仍会在 atom 中使用 Airbnb 样式指南的两个空格规则引发错误? - why does Eslint throws error with the Airbnb style guide's two spaces rule in atom even though I have it set to two spaces and hard tabs? 为什么说xxx不是函数 - Why does it say xxx is not a function 如何使用 Airbnb JavaScript 风格指南设置 Prettier - How do I set up Prettier with Airbnb JavaScript Style Guide 如何运行Airbnb javascript样式指南中的代码? - How do I run the code in the Airbnb javascript style guide? 通过解构或forEach进行缩减-迭代和Airbnb JavaScript样式指南 - Reduce with deconstruction or forEach - Iteration and Airbnb JavaScript Style Guide Airbnb的ES6风格指南功能推荐 - Airbnb's ES6 style guide recommendation about functions 为什么说.setDescription不是函数? (RichEmbed in JavaScript) - why does it say .setDescription is not a function? (RichEmbed in JavaScript) 为什么 Firebug 说 toFixed() 不是函数? - Why does Firebug say toFixed() is not a function?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM