我对Javascrpt的构造函数如何工作感到非常困惑;尽管使用该语言已有好几年了(大多数情况下它就像是LISP的半命令版本),但我想更多地了解对象应该如何工作。
鉴于此代码:
function Foo(x) {
return {
bar: function() { return x; }
};
}
致电myFoo = Foo(5)
和myFoo = new Foo(5)
有什么区别?或者,换句话说,Javascript 中的构造函数究竟是什么?
答案 0 :(得分:48)
致电
myFoo = Foo(5)
和myFoo = new Foo(5)
有什么区别?
该代码没有区别,因为它返回一个对象,spec表示:
- 让结果成为调用F的 [[Call]] 内部属性的结果,提供 obj 作为{{1} }值并提供传递到 [[Construct]] 的参数列表作为args。
- 如果
this
为Type(result)
,则返回结果。
由于该函数返回一个Object结果,因此使用其结果。如果它没有返回一个对象,或者如果它检查Object
,你会发现它有所不同,例如,如果你把它重写为:
this
无论如何,JavaScript中的
function Foo(x) { if (!(this instanceof Foo)) { return new Foo(x); } this.bar = function() { return x; }; } // Now instanceof works. alert((new Foo) instanceof Foo);
会做什么?
new
运算符会调用函数,new
绑定到新创建的this
,其原型是该函数的Object
属性。
对于用户定义的函数,
prototype
相当于
new f(a, b, c)
请注意,语言规范实际上定义了两个操作[[Call]]和[[Construct]]的函数,因此在某些极端情况下// Create a new instance using f's prototype.
var newInstance = Object.create(f.prototype), result;
// Call the function
result = f.call(newInstance, a, b, c),
// If the result is a non-null object, use it, otherwise use the new instance.
result && typeof result === 'object' ? result : newInstance
表现得很奇怪。
例如,绑定和内置函数:
new
应定义一个函数,在调用时,只需调用var g = f.call.bind(f);
,因此f
在所有方面都应与g
相同,但
f
产生
new g()
因为内置函数TypeError: function call() { [native code] } is not a constructor
支持 [[Call]] 但不支持 [[Construct]] 。
Function.prototype.call
在Function.prototype.bind
和常规电话周围的行为也不同。 new
值在调用时始终是绑定的thisValue,但在使用this
时是新构造的实例。
答案 1 :(得分:13)
在这个特定的例子中,最终结果没有区别。
这是因为您的Foo
函数正在返回对象实例。
new
运算符仅在函数返回原始值时才返回从构造函数的原型继承的新创建的对象(或者它不返回任何内容,技术上是{ {1}}值)。
例如:
undefined
当您返回一个对象时,从构造函数原型继承的新创建的对象将被丢弃:
function Foo () {
return 5; // or "", or null, or no return statement at all (undefined)
}
var foo = new Foo();
typeof foo; // "object"
foo instanceof Foo; // true
Foo.prototype.isPrototypeOf(foo); // true
另见:
答案 2 :(得分:5)
在这种情况下,当您返回一个新对象时没有任何区别。它可以改写为:
function Foo(x){
this._x = x;
}
Foo.prototype.bar = function() {
return this._x;
}
每次调用new Foo
时都会使用此语法,它将创建一个属性为_x
的新对象。好处是bar
函数将被存储一次并重用于多个Foo实例。使用多次调用Foo()
的问题中的代码将为每个实例创建一个条形函数。因此,将函数附加到原型而不是将它们直接放在对象上会使内存更轻松。
可以在MDC找到原型工作方式的完整细分。