本文已参与「新人创作礼」活动,一起开启掘金创作之路。
1. Object构造函数创建
const Person = new Object();
Person.name = 'Jane';
Person.age = 21;
2. 使用对象字面量表示法来创建对象
const Person = {}; // 等同于 const Person = new Object();
const Person = { name: "Jane", age: 21 }
1 和 2 的缺点是他们用同一个接口创建很多对象,会产生大量的重复代码。
3. 工厂模式
用于抽象创建特定对象的过程。
function createStudent(name, age) {
const student = new Object();
student.name = name;
student.age = age;
student.sayName = function() {
alert(this.name);
}
return student;
}
const student1 = createStudent('Jane', 33);
缺点:无法确定返回的对象究竟是一个什么类型
4. 构造函数模式
ECMAScript 中的构造函数是用于创建特定类型的对象。比如 Object 或者 Array 这种原生的构造函数,运行时可以直接在执行环境中使用。
同样地,我们也可以自定义构造函数,以函数的形式为自己的对象类型定义属性和方法
function Student(name, age) {
this.name = name;
this.age = age;
this.sayName = function() {
alert(this.name);
}
}
const stu1 = new Student('Jane', 33);
const stu2 = new Student('Yammy', 22);
要创建 Student 实例,应使用 new 操作符。以这种方式调用函数会执行如下操作:
stu1.constructor === Student; //true
stu2.constructor === Student; //true
constructor 本来是用来标识对象类型的。不过,一般认为 instanceof 操作符是确定对象类型更可靠的方式。
stu1 instanceof Student // true
stu1 instanceof Object // true // 这里之所以会被认为是 Object 的实例,是因为所有自定义对象都继承自 Object
stu2 instanceof Student // true
构造函数与普通函数的唯一区别就是调用方式不同。除此之外,构造函数也是函数,并没有把某个函数定义为构造函数的特殊语法。任何函数只要使用 new 操作符调用就是构造函数,而不使用 new 操作符调用的函数就是普通函数。
优点:相比工厂模式,自定义构造函数可以确保实例被标识为特定类型。
缺点:构造函数定义的方法会在每个实例上都创建一遍。就前面的例子,stu1 和 stu2 都有名为 sayName 的方法,但是这两个方法不是同一个 Function 实例。但是它们都是在做同一件事情。没有必要定义两个不同的 Function 实例。
5. 原型模式
每个函数都会创建一个 prototype 属性,这个属性是一个对象,包含应该由特定引用类型的实例共享的属性和方法。
function Student() {}
Student.prototype.name = 'Jane';
Student.prototype.age = 33;
Student.prototype.sayName = function() {
alert(this.name);
}
const stu1 = new Student();
const stu2 = new Student();
stu1.sayName === stu2.sayName // true
使用原型可以让所有对象实例共享所包含的属性和方法。
6. 构造函数 + 原型模式
function Student(name, age, job) {
this.name = name;
this.age = age;
}
Person.Student.sayName = function() {
console.log(this.name)
};
7. Class
ES6 的 class 可以看做只是一个语法糖,它绝大部分功能,ES5 也可以做到,class 写法只是让对象原型的写法更加清晰、更加面向对象编程的语法而已。
class Student {
constructor(name) {
this.name = name;
}
sayName() {
console.log(this.name)
}
}
class的所有方法都定义在类的原型 prototype 属性上面。等同于:
Student.prototype = {
constructor(name) {
this.name = name;
},
sayName() {
console.log(this.name)
}
}