【问题标题】:What does this Animal = function Animal do?这个 Animal = function Animal 有什么作用?
【发布时间】:2013-04-22 16:03:16
【问题描述】:

我正在尝试理解 CoffeeScript 生成的这段 JavaScript 代码。

我习惯于将函数定义为:

  • function Animal(name) {...}
  • var Animal = function(name){...};

但 CoffeeScript 会产生以下结果:

var Animal = (function() {
  function Animal(name) {
    this.name = name;
  }

  return Animal;

})();

问题:

  • 在匿名函数中创建“命名”函数有什么作用?
  • 这样定义 Animal 函数与两种项目符号方式中的一种相比有什么优势?

奖金问题 这些是等价的吗?

//Methodology #1
function Animal(name) {...}
//Methodology #2
var Animal = function Animal(name) {...};

【问题讨论】:

    标签: prototypal-inheritance prototype-programming javascript


    【解决方案1】:

    像这样定义 Animal 函数与直接定义 Animal 函数相比有什么优势? 两种项目符号方式之一?

    1. 函数的名称仍会显示在调试控制台中
    2. 尽管有名称,但该函数不会污染全局命名空间,因为它的作用域是匿名包含函数的本地范围,并且它可以作为闭包使用。

    关于你的奖金问题:

    http://javascriptweblog.wordpress.com/2010/07/06/function-declarations-vs-function-expressions/

    【讨论】:

      【解决方案2】:
      1. 在匿名函数中创建“命名”函数有什么作用?

        更新

        这只是true for IE8 because of the JScript Bug,在现代(和健全的)浏览器中,使用命名函数表达式时,Animal 不会在上下文命名空间中注册。

        它阻止函数声明在上下文中注册函数名(可能是全局命名空间)。这意味着如果你这样做:

        var Tiger = function Animal() {};
        

        TigerAnimal 都在全局命名空间中注册,而这个:

        var Tiger = function() { function Animal() {}; return Animal; };
        

        只在全局命名空间中注册Animal

      2. 像这样定义 Animal 函数与两种项目符号方式中的一种相比有什么优势?

        更新

        同样,如果适用于比 IE8 更现代的浏览器,这将无效。在这些情况下,您可以使用命名函数表达式而无需担心您的上下文。

        优点是在保持上下文(同样,可能是全局)命名空间干净的同时,您仍然可以为您的对象创建一个命名构造函数。这意味着:

        var Tiger = function() {};
        var t = new Tiger();
        t.constructor // is an anonymous function() {}
        

        声明性不如

        var Tiger = function() { function Animal() {}; return Animal };
        var t = new Tiger();
        t.constructor // is a function Animal()
        Animal //=> is not defined
        

        这会污染全局命名空间或上下文命名空间,可能不需要注册Animal

        var Tiger = function Animal() {};
        var t = new Tiger();
        t.constructor // is a function Animal()
        Animal //=> returns function Animal();
        
      3. 这些是等价的吗?

        更新

        这适用于所有浏览器。

        没有。在第一个中,您通过名称Animal 声明一个函数,而在第二个中,您将一个名称为Animal 的函数分配给一个名称为Animal 的变量,这被称为命名函数表达式。首先,查找通过函数名进行,其次,查找通过变量名进行。这是因为function declarations can not overwrite function expressions:函数声明是在脚本加载的上下文中加载的,而表达式赋值是在脚本执行时执行的:

        function a() { 
          var b = function() { return 3; }; 
          return b(); 
          function b() { return 9; } 
        }
        
        a() //=> returns 3;
        

      【讨论】:

      • 1 不正确。命名函数表达式不会将它们的名称转换为变量。这几乎使其余的答案无效。
      • @cHao 我没有说它泄漏到外部范围,我只是说它们是在给定的上下文(可能是全局命名空间)中注册的。重新表述它,所以现在应该很清楚了。
      • 仍然不正确。当我说var x = function y() { }; 时,我可以看到x,但y 不存在任何地方,但函数中。
      • 也就是说,var x = function y() { y(); }; x(); 工作(除了溢出调用堆栈),而 var x = function y() { }; y(); 根本不运行。 (“ReferenceError:y 未定义”,node.js 和 Chrome 说。)
      • @cHao 自己去IE8看看。 Here's some more quirks to think of我相应地更新了问题。
      【解决方案3】:

      “在匿名函数中创建“命名”函数有什么作用?”

      它只是创建一个新函数,该函数在它所嵌套的函数内的变量范围内是本地的。

      “像这样定义 Animal 函数与两种项目符号方式中的一种相比有什么优势?”

      鉴于显示的代码,没有特别的优势,但如果该外部函数内部还有其他变量,则该内部函数可以引用它们以提供对它们的受控访问(因为否则这些变量将无法从外部访问外部函数).

      这是可能的,因为 JavaScript 函数形成了所谓的闭包,这意味着即使从该变量范围中删除,它们也会携带其原始变量范围。

      额外问题这些是等价的吗?”

      到原始代码?是的,它们基本上是等价的。

      主要是对彼此。主要区别在于函数声明 (Method 1) 是“提升的”,这意味着它们在其作用域的顶部可用,因此您可以在定义它们之前实际使用它们。

      函数表达式只有在表达式被计算后才可用。


      请注意,所有函数都有名称,因此它们都会显示在调试控制台中。此外,所有函数最终在同一个变量范围内。

      【讨论】:

        【解决方案4】:

        你熟悉OOP(面向对象编程)吗?

        因为您在这里看到的是尝试在 JavaScript 中定义对象,即使 JavaScript 中没有 class 关键字。

        如果你对 Java 有一点了解(它与 JavaScript 几乎没有任何关系),那么这应该看起来很熟悉:

        public class Animal { // creating a class
            private String name; // declaring its attributes
        
            public Animal(String name) { // declaring constructor
                this.name = name; // assigning value to the attribute
            }
        }
        

        您提供的 JavaScript 代码基本上做同样的事情,例如创建一个类(某种增强类型),它同时具有 属性(分配给它的变量)和 方法 em>(分配给它的功能)。

        所以这段代码

        function Animal(name) {
            this.name = name;
        }
        

        创建Animal 类。

        问题是,在 JavaScript 中,实际上并没有任何 class 的概念,而只有 objects 的概念。因此,您在这里创建一个变量,然后分配以下函数的 result

        var Animal = (function() {
            // some code here
        })
        (); // note the parenthesis here that means the function is called
        

        然后,定义一个constructor,并返回包含该函数的对象。

        所以在执行结束时,var Animal 包含一个构造函数,因此任何对象都可以像这样初始化:̀var myAnimal = new Animal('Panther');

        希望对您有所帮助。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-08-29
          • 1970-01-01
          • 1970-01-01
          • 2014-04-24
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多