有名函数表达式全面解析(翻译教程)

2016-02-20 00:58 3 1 收藏

今天天气好晴朗处处好风光,好天气好开始,图老师又来和大家分享啦。下面给大家推荐有名函数表达式全面解析(翻译教程),希望大家看完后也有个好心情,快快行动吧!

【 tulaoshi.com - Web开发 】

简介

Surprisingly, a topic of named function expressions doesn’t seem to be covered well enough on the web. This is probably why there are so many misconceptions floating around. In this article, I’ll try to summarize both - theoretical and practical aspects of these wonderful Javascript constructs; the good, bad and ugly parts of them.

在互联网上很难找到一篇对有名函数表达式讲述的比较全面的文章。这也可能是为什么对此问题有那么多的误解的原因。在这篇文章中,我将试图从理论和实践两个方面总结这些精彩的javascript结构,他的精华、鸡肋和糟粕。

In a nutshell, named function expressions are useful for one thing only - descriptive function names in debuggers and profilers. Well, there is also a possibility of using function names for recursion, but you will soon see that this is often impractical nowadays. If you don’t care about debugging experience, you have nothing to worry about. Otherwise, read on to see some of the cross-browser glitches you would have to deal with and tips on how work around them.

简而言之,有名函数表达式只对一件工作有用,在调试器和性能测试器中描述函数的名称。当然还有可能在递归调用中使用函数名称,但是你将很快看到在当下他通常不大实用。如果你不担心调试的问题,那么你就不用担心了,甚至不去使用有名函数表达式。否则,继续读下去,你将看到你可能已经遇到的跨浏览器问题和一些解决这些问题的方法。

I’ll start with a general explanation of what function expressions are how modern debuggers handle them. Feel free to skip to a final solution, which explains how to use these constructs safely.

下面我们先来介绍一下什么是函数表达式,和现代的调试器如何处理他们呢。你也可以随时跳转到最后的解决方案,那里将说明如何安全的使用这些结构

函数表达式和函数定义

One of the two most common ways to create a function object in ECMAScript is by means of either Function Expression or Function Declaration. The difference between two is rather confusing. At least it was to me. The only thing ECMA specs make clear is that Function Declaration must always have an Identifier (or a function name, if you prefer), and Function Expression may omit it:

在ECMAScript中有两种简单的创建函数对象的方法,一种是函数表达式,一种是函数声明。两者的区别让人比较困惑,至少对我是这样。ECMS规范中唯一澄清了的是函数声明必须含有一个标示符(如果你喜欢,可以称他为函数名),但是函数表达式可以省略他。

FunctionDeclaration :
function Identifier ( FormalParameterList opt ){ FunctionBody }

FunctionExpression :
function Identifier opt ( FormalParameterList opt ){ FunctionBody }

We can see that when identifier is omitted, that something can only be an expression. But what if identifier is present? How can one tell whether it is a function declaration or a function expression - they look identical after all? It appears that ECMAScript differentiates between two based on a context. If a is part of, say, assignment expression, it is considered a function expression. If, on the other hand, is contained in a function body or in a (top level of) program itself - it is parsed as a function declaration.

我们可以看到,当标示符被省略的时候,这样的结构只能是一个函数表达式。但是当标示符出现的时候情况是怎样的呢。他究竟是一个函数声明还是一个函数表达式呢,他们看上去是完全一样的。但是ECMAScript是通过上下文来区分两者的。如果function foo(){}是一个赋值表达式的一部分,他就被认为是函数表达式。相反,如果function foo(){}包含在一个函数体中,或者在程序的最上层的代码中,他就被解释成为一个函数声明。

  function foo(){}; // 声明,因为作为最上层程序的一部分declaration, since it's part of a Program
  var bar = function foo(){}; // 表达式,因为是复制表达式的一部分expression, since it's part of an AssignmentExpression

  new function bar(){}; // 表达式,因为他是New表达式的一部分。expression, since it's part of a NewExpression

  (function(){
    function bar(){}; // 声明,因为是函数图的一部分declaration, since it's part of a FunctionBody
  })();

There’s a subtle difference in behavior of declarations and expressions.

(本文来源于图老师网站,更多请访问https://www.tulaoshi.com/webkaifa/)

声明和表达式在作用上有这细微的差别。

First of all, function declarations are parsed and evaluated before any other expressions are. Even if declaration is positioned last in a source, it will be evaluated foremost any other expressions contained in a scope. The following example demonstrates how function is already defined by the time is executed, even though it’s being declared right after it:

首先,函数声明是在所有表达式之前被解析和求值。即使声明被放在代码的最后,他也会在包含它的作用域内的所有表达式之前被求值。下面的例子将说明即使fn函数在alert执行之后才被声明,但是在alert被执行的时候fn函数已经被定义了。

  alert(fn());

  function fn() {
    return 'Hello world!';
  }

Another important trait of function declarations is that declaring them conditionally is non-standardized and varies across different environments. You should never rely on functions being declared conditionally and use function expressions instead.

(本文来源于图老师网站,更多请访问https://www.tulaoshi.com/webkaifa/)

函数声明的另外一个重要的特点是,在条件语句中声明他们的情况在ECMA标准中是没有说明的,并且在不同的环境中(也就是不同的浏览器)中是不同的。因此你不能依赖函数的条件声明,而是应该使用函数表达式来代替。

  // 千万不要这样做Never do this!
  // 有些浏览器会声返回first的foo函数Some browsers will declare `foo` as the one returning 'first',
  // 有些浏览器则会声明返回second的foo函数while others - returning 'second'

  if (true) {
    function foo() {
      return 'first';
    }
  }
  else {
    function foo() {
      return 'second';
    }
  }
  foo();

  //作为替代你可以使用函数表达式 Instead, use function expressions:
  var foo;
  if (true) {
    foo = function() {
      return 'first';
    }
  }
  else {
    foo = function() {
      return 'second';
    }
  }
  foo();

Function expressions can actually be seen quite often. A common pattern in web development is to fork function definitions based on some kind of a feature test, allowing for the best performance. Since such forking usually happens in the same scope, it is almost always necessary to use function expressions. After all, as we know by now, function declarations should not be executed conditionally:

函数表达式可能更常见一些。在web开发中的一个普通的模式就是根据一些某种功能测试的情况来fork函数定义,允许达到最好的性能。既然这个fork通常发生在同一个作用域内,所以他需要使用函数表达式。毕竟,如我们所知,函数定义不应该被条件执行

  var contans = (function() {
    var docEl = document.documentElement;

    if (typeof docEl.compareDocumentPosition != 'undefined') {
      return function(el, b) {
        return (el.compareDocumentPosition(b) & 16) !== 0;
      }
    }
    else if (typeof docEl.contains != 'undefined') {
      return function(el, b) {
        return el !== b && el.contains(b);
      }
    }
    return function(el, b) {
      if (el === b) return false;
      while (el != b && (b = b.parentNode) != null);
      return el === b;
    }
  })();
有名函数表达式

Quite obviously, when a function expression has a name (technically - Identifier), it is called a named function expression. What you’ve seen in the very first example - - was exactly that - a named function expression with being a function name. An important detail to remember is that this name is only available in the scope of a newly-defined function; specs mandate that an identifier should not be available to an enclosing scope:

非常显然那,当一个函数表达式含有函数名(从技术上讲就是一个标示符),他就被称作有名函数表达式。在你看到的第一个例子中 var bar=function foo(){}就是这样,他是一个以foo作为函数名的有名函数表达式。最重要的一个细节就是这个函数名只有在新定义的函数的作用域内才可访问,ECMA要求一个标示符不应该被一个封闭的作用域所访问

  var f = function foo(){
    return typeof foo; // foo在内部作用域可以被访问 "foo" is available in this inner scope
  };
  //‘foo’在外部不可见 `foo` is never visible "outside"
  typeof foo; // "undefined"
  f(); // "function"

So what’s so special about these named function expressions? Why would we want to give them names at all?

It appears that named functions make for a much more pleasant debugging experience. When debugging an application, having a call stack with descriptive items makes a huge difference.

因此,为什么这些有名函数表达式如此特别?为什么我们想要给他们名字呢。

可以看到有命名的函数在调试过程中可能更加方便一些。当调试一个应用程序的时候拥有一个含有描述项的调用栈会有很大的不同

来源:https://www.tulaoshi.com/n/20160220/1632959.html

延伸阅读
标签: Web开发
今天我们将先简要地看一下正则表达式,然后再看一下MooTools提供的一些让正则表达式更容易使用的功能。如果你还不熟悉怎么使用正则表达式(regular expression(regex)),我强烈建议你花一定量的时间好好看一下这篇文章中的一些链接,尤其是文章结尾更多学习部分的链接。我们今天只是讲一讲正则表达式最基本的用法,正则表达式能做的远远...
标签: Web开发
正则表达式是一种文本模式,包括普通字符(例如,a 到 z 之间的字母)和特殊字符(称为元字符)。模式描述在搜索文本时要匹配的一个或多个字符串。   正则表达式示例 表达式 匹配 /^\s*$/ 匹配空行。 /\d{2}-\d{5}/ 验证由两位数字、一个连字符再加 5 位数字组成的 ID 号。 /\s*(\S+)(\s[^]*)?[\s\S]*\s*\/\1\s*/ ...
标签: Web开发
正则表达式在PHP中被用来处理复杂的文字串。支持正则表达式的函数有: ereg()ereg replace()eregi replace()split() 这些函数都将正则表达式作为他们的第一个参数。PHP使用POSIX扩展规则表达式(使用POSIX 1003.2)。要找到所有的关于POSIX扩展规则表达式的描述,请查看包括在PHP发行版本之内的regex man页面。 Examp...
正则表达式简介 翻译:NorthTibet 原文出处:Regular Expressions 有些新手对正则表达式不是很熟悉,有必要在此作一简单回顾。如果你是正则表达式高手,可以不用看这一部分。 正则表达式是描述字符串集的字符串。例如,正则表达式“Mic*”描述所有包含“Mic”,后跟零个或多个字符的字符串。Mickey、Microsoft、Michelangelo...
标签: autocad教程
    用户在Auto CAD 系统中使用D IE SEL表达式时,如果系统变量MACROTRACE的值置为1,则执行DIESEL表达式,会在命令提示行显示运行结果及错误信息。该变量的缺省值为0。     例如,将变量MACROTRACE置为1后,在用DIESEL表达式给MODEMACRO赋值时,如果在“getvar”和“dwgname”之间不加“,”...

经验教程

875

收藏

14
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部