代码之家  ›  专栏  ›  技术社区  ›  Tomasz Zieliński

JavaScript-函数核心对象的行为

  •  5
  • Tomasz Zieliński  · 技术社区  · 14 年前

    据我所知,在JavaScript(Gecko变体)中:

    var a = new A();
    

    是这样的语法糖:

    var a = {};
    a.__proto__ = A.prototype;
    A.call(a);
    

    正因为如此, A() (相当于 呼叫() ?) 和 新A() 应该产生两个不同的结果,如下所示:

    >>> new Date()
    Fri Nov 19 2010 01:44:22 GMT+0100 (CET) {}
    >>> typeof new Date()
    "object"
    
    >>> Date()
    "Fri Nov 19 2010 01:44:42 GMT+0100 (CET)"
    >>> typeof Date()
    "string"
    

    到现在为止,一直都还不错。

    但是,核心目标 Function 行为方式不同:

    >>> Function('return 123;')
    anonymous()
    >>> typeof Function('return 123;')
    "function"
    >>> Function('return 123;')()
    123
    >>> new Function('return 123;')
    anonymous()
    >>> typeof new Function('return 123;')
    "function"
    >>> new Function('return 123;')()
    123
    

    我是不是错过了一些小事?

    6 回复  |  直到 14 年前
        1
  •  3
  •   bobince    14 年前

    语言级别的JavaScript没有指定使用构造函数的特定标准方式。当您定义自己的构造函数时,可以选择将其作为构造函数调用(使用 new ),作为一个函数(返回一个新对象),或使其与之一起工作。

    我是不是错过了一些小事?

    不是真的。这个 Function 构造函数被定义为即使没有 新的 ,根据ECMAScript第15.3.1节:

    什么时候? 功能 作为函数而不是构造函数调用,它创建并初始化 new Function 反对。因此函数调用 Function(...) 相当于对象创建表达式 new Function(...) 同样的论据。

    这个 Date 另一方面,函数(由ECMAScript第15.9.2节定义)被定义为返回字符串:

    当日期作为函数而不是构造函数调用时,它返回一个表示当前时间(UTC)的字符串。

    注:函数调用 Date(...) 与具有相同参数的对象创建表达式new Date(…)不同。

    这里有一个注释,因为许多构造函数也可以在没有 新的 . 这并不是因为所有构造器函数都应该被允许作为纯函数工作,而是因为这正是JavaScript自早期Netscape以来一直做的事情。网景公司想不出什么特别的 Function() 所以它复制了 新的 功能。他们不太注意使语言连贯。

    如果你是理智的,你就不会设计一种语言的默认类库。但是JavaScript不是一种理智的语言。这是一个很快就失控的黑客,在任何人花时间改进它的设计之前,就已经获得了大众的欢迎。期待它始终如一的表现,你只会失望。

        2
  •  2
  •   Community CDub    8 年前

    这个 Function constructor called as a function 与在表达式中使用 new 接线员,情况在说明书中有描述。

    从第15.3.1节: 作为函数调用的函数构造函数

    我是。。。

    还有一些内置构造函数的行为与此类似,例如 Array constructor called as a function :

    Array(1,2,3);     // [1,2,3]
    new Array(1,2,3); // [1,2,3]
    

    其他构造函数,如 原语值包装器 ( Boolean , String , Number Date )表现得不一样。

    前三个如果你用不用 新的 接线员,他们只是 类型转换 ,例如:

    typeof Number("20"); // "number"
    typeof String(0xFF); // "string"
    typeof String({toString: function () { return 'foo' }}); // "string"
    typeof Boolean(""); // "boolean"
    typeof Boolean(0); // "boolean"
    

    如果你把它们和 新的 接线员,他们会回来的 包装器对象 :

    typeof new Number(20); // "object"
    typeof new String('foo'); // "object"
    typeof new Boolean(true); // "object"
    

    这种物体叫做 原始包装 ,它们有一个名为 [[PrimitiveValue]] 它们存储其潜在价值的地方(更多 Objects vs Primitives ).

    使用创建的对象 日期 构造器也是 原始包装 它们的基本值是 时间价值 .

    的语义 日期 如果 it's called as a function ,它将返回“表示当前时间(UTC)的字符串”。

        3
  •  1
  •   Community CDub    8 年前

    你可以从构造器中判断你是否被调用过 new 或者不-如果 新的 , this instanceof MyClass ;如果不是 新的 , this === window (前提是它是一个顶级对象——正如gnarf指出的那样 Namespace.MyClass() , this == Namespace ).

    很有可能(有些人比其他人更喜欢它)把它放在构造器的顶部 if (this instanceof MyClass) return new MyClass(); (自然地,考虑到参数);然后可以调用构造函数 新的 同样的结果。

    讨论这个问题的一个问题是 Is JavaScript 's “new” Keyword Considered Harmful? . 还有其他的。

        4
  •  1
  •   user166390user166390    14 年前

    可以 从JavaScript中的一个ctor“return”返回一个不同的值——一些内置函数(例如Date)的工作方式是这样的(函数也是这样,但它的工作方式不同于Date:-)。 我不知道在哪里有记录 --在ECMA 262中,请参阅其他答案。

    下面是一个虚构的示例,演示如何创建一个类似“Function”(在FF中)的ctor:

    function X() {
      // but this has issues with nesting in some cases
      if (!(this instanceof X)) {
        return new X()
      } else {
        this.y = 2
      }
    }
    X().y // => 2
    

    但是,我不知道ECMA规范是如何定义的。。。无论如何,返回的结果完全取决于被调用的函数。 --再次参见ECMA 262。

        5
  •  0
  •   Darko    14 年前

    这是因为 Function() 返回函数,并且 new Function() 构造一个函数,从而获得相同的输出。

        6
  •  0
  •   Ruan Mendes    14 年前

    不知道你的问题是什么。。。我可以告诉你的是,基本对象中有代码,允许你用new和without new调用它,但是它们的行为有点不同。

    typeof Number(5) == "number"
    typeof new Number(5) == "object"
    
    typeof Boolean(0) == "boolean"
    typeof new Boolean(0) == "object"
    

    对基本类型调用new将返回包装为对象的原语。

    我写了一篇关于创建使用或不使用新操作符的构造函数的博客 http://js-bits.blogspot.com/2010/08/constructors-without-using-new.html 我不用,但很有趣。它将让您了解如何根据是否使用new调用函数来更改函数的行为。。。。

    即使在这咆哮之后,我仍然不确定你的问题是什么。。。