JavaScript 创建对象几种方式

104 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

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) 
    } 
 }