ECMA-262中,把对象定义为:”无序属性的集合,其属性可以为基本类型值、对象或者函数。”而一般我们要创建对象(更准确一点叫做创建对象实例)时,会使用 new 操作符。最简单的如 new Object() ,然后我们把创建对象实例的那个东西(也就是 new 操作符后面跟着的那个东西,一般都是一个函数)叫做构造函数(有人也叫做构造器)。再然后我们会把 new Object() 的返回值赋值给一个变量如 obj ,写成 var obj=new Object(); ,而后我们就会对obj进行各种操作,但其中到底发生了什么?
当 new Foo(...) 被执行
引用 MDN 上关于当
new Foo(...)被执行,会发生如下事情:
- 创建一个从
Foo.prototype继承的新对象;- 构造函数
Foo使用指定的参数调用,并将Foo中的this绑定到新创建的对象。new Foo相当于new Foo(),即如果没有指定参数列表,则使用无参调用Foo;- 构造函数返回的对象成为整个
new表达式的结果。如果构造函数没有显式地返回一个对象,那么将使用步骤1中创建的对象。(通常构造函数不返回值,但是它们可以选择这样做,如果它们想要覆盖正常的对象创建过程。)
上面那段说白了就是:
- 使用
new操作符时,会创建一个新对象,该新对象的__proto__属性指向其构造函数的原型,即Foo.prototype; - 构造函数中的
this会指向新对象; - 执行构造函数中语句;
- 如果构造函数定义了返回值且返回值是对象(包括数组、函数之类的),则返回值为这些对象;如果构造函数未定义返回值(默认返回
Undefined)或定义的返回值是基本类型(Undefined类型、Null类型、Boolean类型、Number类型、String类型),则返回new创建的那个新对象。
需注意的是:新对象的 __proto__ 属性指向其构造函数的原型,即 Foo.prototype,而不是指向 Foo 。 Foo.prototype 为创建 Foo (一般为使用 function Foo(){...})时创建的的属性,prototype中包括一个名为 constructor 的属性,该属性才是指向 Foo。
2019.11.07 update
__proto__为浏览器(Mozilla)为访问[[prototype]]私有属性而定义的,类似的访问[[class]]属性要通过Object.prototype.toString
举例说明:
字面量定义 prototype
还需要注意的一点为,如果通过字面量形式定义 prototype 时,如下:
1 | function Person(){ |
此时 Person.prototype 的 constructor 属性就不是指向 Person 了 而是指向默认的 Object ,因为字面量形式相当于重写 prototype,如需像关键字声明那样使 constructor 指向 Person,需在字面量中手动声明,这个要特别注意。如下:
1 | function Person(){ |
例题
设计一个工具函数extend(A, B), 使 A 继承 B
1 | function extend(A, B) { |

