一、构造对象的几种方式
1.字面量法:
var person1 = {
name: 'peter',
age: 18,
sex: 'boy',
getAge: function() {
return this.age;
}
}
var person2 = {
name: 'john',
age: 22,
sex: 'boy',
getAge: function() {
return this.age;
}
}
字面量法就是简单的key:value直接创建,但是有以下两个缺点:
- 构造麻烦。每次操作都要给所有的变量赋值,都是重复操作的复制粘贴代码很多。
- 每个使用者都需要了解详细的内部细节,即使只是想个性化改变下name。
2. 函数自动化法:
function createPerson(name, age) {
return {
name: name,
age: age,
getAge: function() {
return this.age;
}
}
}
var person1 = createPerson('peter', 18);
- 优点:使用此法简化了构造的过程,每次构造只要调用函数并传入对应的参数即可。也不需要知道内部实现的逻辑。
- 缺点:函数返回的都是一个Object类型的对象,辨识度不高。
3. 构造函数法:
function Person(name, age) {
this.name = name;
this.age = age;
this.getAge = function() {
return this.age;
}
}
var person1 = new Person('peter', 18);
function Car(speed) {
this.speed = speed;
}
var car1 = new Car(50);
用这种方法构造出来的对象类型可以自由定义,比如上面的person1的类型对象是Person,car1是Car,很好区分。如果用第二种的话则他们的类型都是Object。
二、new的过程发生了啥
也许有些小伙伴会有疑惑,为啥会有个new,而不是直接执行方法,这个new到底做了些啥?其实,在new的过程中,主要做了这三件事:
- 创建一个空的对象,并将该对象的proto指向了Person.prototype。
- 执行函数,函数里面对this操作相当于对这个新建的空的对象操作。
- 函数执行完毕之后,返回这个空的对象。

原型图
如上图,是构造函数法代码的简单原型图。每个对象都有一个_proto_,每个方法都有一个prototype,而new的最重要一步就是将生成空对象的_proto_指向了Person的prototype。
三、new一些补充
- new本身就能执行构造函数,所以后面加不加括号都无所谓,但是为了表示是个函数,推荐加上括号。
- 若构造函数前不加new,则相当于普通的执行方法,就不再执行上面说的new的过程,会导致其中的this不再指向实例对象,所以记得加new。若普通函数(内部没有this)加new,则返回一个空对象。
- 在构造函数里,可以通过new.target获得当前的构造函数,若返回undefined则证明当前没有使用new操作。另一种方法是判断
this instanceof 构造函数,看是否返回true来判断是否使用new,若为false则返回new 构造函数()。
function f() {
if (!new.target) {
throw new Error('请使用 new 命令调用!');
}
}
f(); // Uncaught Error: 请使用 new 命令调用!
- 构造函数的最后不需要return。若加了return且返回了一个对象,则会用该对象替换当前创建的实例对象。若返回基本数据类型则忽略返回原来实例对象。
var Human = function (){
this.age = 18;
return { age: 20 };
};
(new Human()).age; // 20
var Human = function () {
this.age = 18;
return 66;
};
(new Human()) === 66; // false