JavaScript - Function核心对象的行为

时间:2010-11-19 00:56:24

标签: javascript

据我了解,在JavaScript(Gecko变体)中:

var a = new A();

是这样的语法糖:

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

因此, A()(相当于 A.call()?)和新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 个答案:

答案 0 :(得分:3)

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

  

我在这里错过了一些小事吗?

不是真的。即使没有Functionnew构造函数也被定义为可用作构造函数,ECMAScript第15.3.1节:

  

Function作为函数而不是构造函数调用时,它会创建并初始化new Function对象。因此,函数调用Function(...)等同于具有相同参数的对象创建表达式new Function(...)

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

  

当Date作为函数而不是构造函数调用时,它返回表示当前时间(UTC)的String。

     

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

注意就在那里,因为没有new也可以使用很多构造函数。这并不是因为任何总体思维认为所有构造函数都应该被允许作为普通函数工作,但是因为这正是JavaScript自Netscape早期以来一直所做的事情。 Netscape无法想到Function()要做的任何特殊事情,所以它只是重现了new功能。他们没有过多关注语言的一致性。

如果你是理智的话,你不会设计一个语言的默认类库。但JavaScript并不是一种理智的语言。这是一个快速破解,在任何人花费任何时间完善其设计之前就已经失控,实现了大众化。期待它表现一致,你只会感到失望。

答案 1 :(得分:2)

Function constructor called as a function与使用new运算符的表达式中的Array constructor called as a function等效,该情况在规范中有所描述。

来自§15.3.1:函数构造函数被称为函数

  

...

     

因此,函数调用Function(...)等效于具有相同参数的对象创建表达式new Function(...)。

其他内置构造函数的行为与此类似,例如Objects vs Primitives

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

其他构造函数(如创建原始值包装器BooleanStringNumberDate)的构造函数表现不同。

如果你使用前三个调用它们而没有new运算符,它们只执行类型转换,例如:

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

如果您将它们与new运算符一起使用,它们将返回包装器对象

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

这种对象称为原始包装,它们有一个名为[[PrimitiveValue]]的内部属性,用于存储它们的基础值(更多内容在it's called as a function上)。

使用Date构造函数创建的对象也是原始包装它们的基础值是时间值的数字表示。

Date构造函数的语义也已完整描述,如果{{3}},它将返回“表示当前时间(UTC)的字符串”。

答案 2 :(得分:1)

您可以从构造函数告诉您是否已使用new调用 - 如果newthis instanceof MyClass;如果不是newthis === window(前提是它是顶级对象 - 正如gnarf指出的那样,对于Namespace.MyClass()this == Namespace)。

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

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

答案 3 :(得分:1)

可以从JavaScript中的ctor“返回”以返回不同的值 - 一些内置函数(例如Date)就像这样工作(和Function一样,但它的工作方式与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试。

答案 4 :(得分:0)

这是因为Function()返回一个函数,new Function()构造一个函数,因此你得到相同的输出。

答案 5 :(得分:0)

不确定你的问题是什么......我可以告诉你的是,基本对象中包含代码,允许你用新的和没有新的来调用它,但它们的行为有点不同。

typeof Number(5) == "number"
typeof new Number(5) == "object"

typeof Boolean(0) == "boolean"
typeof new Boolean(0) == "object"

在基本类型上调用new会返回包裹为对象的基元。

我写过一篇关于创建构造函数的博客,无论是否使用new运算符http://js-bits.blogspot.com/2010/08/constructors-without-using-new.html我都不使用它,但这是有趣的东西。它将为您提供有关如何根据是否使用new调用函数来改变函数行为的见解....

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