2010-11-19 24 views
5

据我了解,在JavaScript(壁虎变体)这样的:JavaScript的 - 功能的核心对象的行为

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 

我缺少一些小事吗?

+0

你*可以*从JavaScript中的“返回”返回一个不同的值 - 一些内置函数(如日期)像这样工作。我不确定它在哪里被记录。 – 2010-11-19 01:01:20

+2

'a .__ proto__ = A.prototype;'不像Gecko所做的那样。如果在Object.prototype上有一个为'__proto__'定义的setter,它将不会被触发。 并且改变'Function.prototype.call'或'A.call'不会改变构造函数的调用方式。 – 2010-11-19 02:00:58

+0

@pst,请参阅EcmaScript 5章13.2.2 [[构造]]。见http://ecma262-5.com/ELS5_Section_13.htm – 2010-11-19 02:08:15

回答

3

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

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

不是。所述Function构造函数被定义为可使用作为构造,即使没有new,由ECMAScript的部分15.3.1:

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

Date功能,在另一方面,被定义(由ECMAScript的部分15.9.2)返回字符串:

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

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

注意是因为如此多的构造函数也可以使用没有new。这并不是因为任何人都认为所有的构造函数应该被允许作为普通函数工作,而是因为这正是JavaScript早期Netscape时代以来的一贯做法。 Netscape想不到Function()有什么特别之处,所以它只是重现了new的功能。他们没有太注意使语言保持一致。

如果你理智,你不会设计一种语言的默认类库。但JavaScript不是一种理智的语言。在任何人花费时间改进其设计之前,这是一种快速的黑客手段,实现了大众化的流行方式。期待它的行为一致,你只会感到失望。

+0

尽管“快速破解失控”,但它比一些“长期设计”的语言做得更好;-) – 2010-11-19 18:29:13

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?。还有其他的。

+0

好吧,如果它是'Namespace.MyClass()'现在可以呢''这个===窗口'不会是真的吗? – gnarf 2010-11-19 01:06:06

+0

@gnarf:好点。 – 2010-11-19 01:18:00

0

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

1

可以从JavaScript中的ctor返回一个不同的值 - 一些内置函数(如Date)像这样工作(就像函数一样,但它的工作方式与Date :-)不同。 我不确定它在哪里被记录 - 在ECMA 262中,请参阅其他答案。

这里是展示一个可以如何创建工作方式类似于“功能”(在FF)一个构造函数一个人为的例子:

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。

0

不知道你的问题是什么...我可以告诉你的是,基本对象的代码允许你用新的和没有新的称呼它,但它们的行为有点不同。

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我不使用它,但它是有趣的东西。它会告诉你如何改变功能的行为,根据它是否被称为新的或不... ...

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

2

Function constructor called as a function与在new运算符的表达式中使用它相同,在说明书中描述了该情况。

从§ 15.3.1:作为函数调用

Function构造...

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

还有其他内置构造函数,其行为就像这样,例如,Array constructor called as a function

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]]的内部财产,他们在那里存储他们的基础价值(详见Objects vs Primitives)。与Date构造函数创建

目的还原始包装它们的基础值是时间值的数字表示。

Date构造函数的语义也完全描述,如果it's called as a function,它将返回一个“代表当前时间(UTC)的字符串”。