JS的构造函数模式

文章目录

  • 原型模式
  • 动态原型模式

原型模式

在JS中,每一个函数被定义之后,就会为这个函数创建一个prototype属性,该属性指向了这个函数的原型对象。

那原型对象能在对象的构造中发挥多大的作用呢?先看一个例子

function Person(){
    this.name = 'Tom';
    this.age = 22;
    this.sayHi = function(){
        console.log('Hello');
    }
}

let personA = new Person();
let personB = new Person();

console.log(personA.sayHi === personB.sayHi);   //false

可以看到创建的两个person对象的sayHi方法是不一样的,这就意味着每一次Person类的实例被创建都要重新创建一遍sayHi方法,这十分浪费时间跟空间。

而引入原型对象之后,就可以比较好的解决这个问题。

function Person(){
    this.name = 'Tom';
    this.age = 22;
}

Person.prototype.sayHi = function(){
    console.log('Hello');
};

let personA = new Person();
let personB = new Person();

console.log(personA.sayHi === personB.sayHi);   //true

通过原型对象可以在多个实例之间共享一些属性而不必重复创建。

然而使用原型对象也会存在问题,如下面的例子

function Person(){
    this.name = 'Tom';
    this.age = 22;
}

Person.prototype={
    constructor: Person,
    friends: []
};

let personA = new Person();
let personB = new Person();

personA.friends.push('Paul');
console.log(personB.friends);   //['Paul']

在原型中定义了一个friends数组,我用personA来访问friends数组并往里添加了一个’Paul’。然而,在访问personB的friends数组的时候,发现也有’Paul’。

这是因为原型对象解决的就是一个共享的问题,然而成也共享,败也共享。原型对象可能会让一些不需要实例间共享的属性被共享。

解决方法也很简单,只要我们不把不想被共享的属性放进原型对象里就可以了。

动态原型模式

把构造方法和原型对象分开写可能不够优雅,那么动态原型模式就是一种较为优雅的解决方案。

function Person(name, age){
    this.name = name;
    this.age = age;
    
    if(typeof this.saiHi != 'Function'){
        Person.prototype.sayHi = function(){
            console.log('Hello');
        }
    }
}

这个构造函数仅会在第一次调用的时候设置原型对象,因为第一次设置完了之后原型对象上就有了sayHi这个方法。

你可能感兴趣的:(JavaScript)