JavaScript里实例化一个对象的时候,我们常用的方法就是使用new
操作符。
var Foo = function(x, y) {
this.x = x
this.y = y
}
var foo = new Foo(1, 2) // Foo {x: 1, y: 2}
那么new
操作符到底做了哪些工作?我们可以看一下foo
这个对象到底是一个怎样的对象。
首先,foo
本身是一个对象,然后,他本身有两个属性,x
跟y
。同时,在大多数浏览器的控制台上,我们还能看到一个颜色稍浅的属性,叫__proto__
,他有两个属性,constructor
跟__proto__
。
__proto__
是一个访问器属性。他指向的是当前对象本身的[[Prototype]]
,这个[[Prototype]]
并不是一个属性,他只是一个符号,代表的是构造函数Foo
的原型对象Foo.prototype
的,具体可以参考一下MDN上的描述。
foo.__proto__ === Foo.prototype // true
所以,我们大致描述一下
var Foo = function(x, y) {
this.x = x
this.y = y
}
// 1. 创建一个空对象
var foo = {}
// 2. 调用构造函数,并且将构造函数的`this`指向foo
Foo.call(foo, 1, 2)
// 3. foo继承Foo的原型对象
foo.__proto__ = Foo.prototype
等等,虽然我们上面这么写最后foo
的确跟new Foo()
出来的对象是一样的,但是情况并不仅仅这么简单。
我们知道,new
操作符操作的是一个函数,在上面的栗子里,函数Foo
并没有显式地返回任何值,所以执行这个函数之后,返回值是undefined
。当构造函数没有显式地返回一个值的时候,对其执行new
操作之后,会返回这个构造函数实例化之后的对象。
那如果我返回了某个值呢?
var Foo = function(x, y) {
this.x = x
this.y = y
return {
a: this.x
}
}
var foo = new Foo(1, 2) // {a: 1}
foo
就是执行这个函数之后的返回值,那么这个时候new Foo()
跟Foo()
就没有任何区别了,所以通常情况下,我们并不会选择在一个构造函数里返回某个值。
特别要注意的是,如果你在构造函数里返回的不是一个对象,而是一个普通的值,比如说一个Number
类型或者String
类型的值,那么new
之后返回的还是实例化之后的对象。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。