JavaScript中的`new`做什么呢?
我很困惑如何构造函数在Javascrpt中工作; 尽pipe使用了几年的语言(大部分就像是LISP的半必要版本),但我想更多地了解对象应该如何工作。
鉴于此代码:
function Foo(x) { return { bar: function() { return x; } }; }
调用myFoo = Foo(5)
和myFoo = new Foo(5)
什么myFoo = new Foo(5)
? 或者换句话说,Javascript中的构造函数究竟做了什么 ?
调用
myFoo = Foo(5)
和myFoo = new Foo(5)
什么myFoo = new Foo(5)
?
这段代码没有区别,因为它返回一个对象, 规范说:
- 设结果为调用F的[[Call]]内部属性的结果,提供obj作为
this
值,并将传递给[[Construct]]的参数列表提供为args。- 如果
Type(result)
是Object
则返回结果 。
由于该函数返回的是Object的结果,因此使用它的结果。 如果它没有返回一个对象,或者如果它检查了this
,你会注意到一个区别,例如,如果你把它改写为:
function Foo(x) { if (!(this instanceof Foo)) { return new Foo(x); } this.bar = function() { return x; }; } // Now instanceof works. alert((new Foo) instanceof Foo);
无论如何,JavaScript中有什么
new
呢?
new
运算符使该函数被绑定到一个新创build的Object
,该Object
的原型是该函数的prototype
属性。
对于用户定义的function,
new f(a, b, c)
相当于
// 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
注意,语言规范实际上用两个操作[[Call]]和[[Construct]]来定义函数,所以有一些new
行为奇怪的情况。
例如,绑定和内置函数:
var g = f.call.bind(f);
应该定义一个被调用的函数,就是调用f
,所以g
应该和f
在所有方面一样,但是
new g()
产生
TypeError: function call() { [native code] } is not a constructor
因为内build函数Function.prototype.call
支持[[Call]]而不支持[[Construct]] 。
Function.prototype.bind
new
和常规的调用, Function.prototype.bind
也有不同的performance。 this
值在被调用的时候总是绑定thisValue,但是在你使用new
时候是一个新构造的实例。
在这个例子中,最终结果没有任何区别。
这是因为你的Foo
函数正在返回一个对象实例 。
只有当函数返回一个原始值 (或者它不返回任何东西,这在技术上是undefined
值) 时, new
运算符才会返回从构造函数的原型inheritance的新创build的对象。
例如:
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
当你返回一个对象时,从构造函数的原型inheritance的新创build的对象将被丢弃:
function Foo () { return {}; } var foo = new Foo(); typeof foo; // "object" foo instanceof Foo; // false Foo.prototype.isPrototypeOf(foo); // false
也可以看看:
- 构造函数可以返回什么值来避免返回?
- JavaScript:“新”如何在内部工作
在这个例子中,当你返回一个新的对象的时候,没有什么区别。 它可以被重写为:
function Foo(x){ this._x = x; } Foo.prototype.bar = function() { return this._x; }
有了这个语法,每次你调用new Foo
,它将创build一个_x
属性的新对象。 好处是bar
函数将被存储一次,并被重用于Foo的多个实例。 在多次调用Foo()
的问题中,代码将为每个实例创build一个bar函数。 因此,将function附加到原型上而不是直接放在对象上会使内存更轻。
在MDC上可以find原型如何工作的全面细分。