JS 工厂模式、构造函数模式、原型模式、混合模式、动态原型模式,寄生构造函数模式,稳妥构造函数模式

构造函数,原型,实例的关系:

每个构造函数都有一个原型对象(prototype),原型对象都包含一个指向构造函数的指针(constructor),而实例都包含一个指向原型对象的内部指针。


JS 工厂模式、构造函数模式、原型模式、混合模式、动态原型模式,寄生构造函数模式,稳妥构造函数模式_第1张图片
关系图.png

1.工厂模式

function createPerson(name,age,job){
    var o = new Object();  //"原料"
    //"加工"
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function(){
        alert(this.name);
    };
    return o;//"出厂"
}
var person1 = createPerson("a1",12,"程序");
var person2 = createPerson("b1",18,"销售");
console.log(person1.name)
console.log(person2.age)

2.构造函数模式

任何函数,只要通过 new 操作符来调用,那它就可以作为构造函数 ;
任何函数,如果不通过 new 操作符来调用,那它跟普通函数也没有什么两样。

//创建函数
function Person(name,age,job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function(){
        alert(this.name);
    }
}

//当作构造函数使用

var person = new Person('Nicholas',29,'Software Engineer');//this-->person
person.sayName();//'Nicholas'

//当作普通函数调用

Person('Greg',27,'Doctor');//this-->window
window.sayName();//'Greg'
对比

1.没有显式地创建对象;
2.直接将属性和方法赋给了this对象;
3.没有return语句;
4.构造函数都应该以 一个大写字母开头
function Person(){...}
而非构造函数则应该以一个小写字母开头
function person(){...}
5.使用new创建对象
6.能够识别对象(这正是构造函数模式胜于工厂模式的地方)

3.原型模式

在JS中,无论什么时候,只要你创建了一个新函数,就会根据一组特定的规定为该函数创建一个prototype的属性,这个属性指向函数的原型对象。而在默认情况下,所有的原型对象都会自动获得一个constructor(构造函数)属性,这个属性包含一个指向prototype属性所在函数的指针。

function Person(){}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
    alert(this.name);
};
var person1 = new Person();
person1.sayName();//"Nicholas"
var person2 = new Person();
person2.sayName();//"Nicholas"
alert(person1.sayName == person2.sayName);//true

在此,我们将sayName()方法和所有属性直接添加到了Person的prototype属性中,构造函数变成了空函数。与构造函数模式不同的是,新对象的这些属性和方法是由所有实例共享的。换句话说,person1和person2访问的都是同一组属性和同一个sayName()函数。

虽然可以通过对象实例访问保存在原型中的值,但却不能通过对象实例重写原型中的值。如果我们在实例中添加了一个属性,而该属性与实例原型中的一个属性同名,那我们就在实例中创建该属性,该属性将会屏蔽原型中的那个属性

function Person(){}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
    alert(this.name);
};
var person1 = new Person();
var person2 = new Person();
person1.name="Grag";
alert(person1.name);//"grag"---来自实例
alert(person2.name);//"Nicholas"--来自原型

通过使用delete操作符可以完全删除实例属性

var person1 = new Person();
var person2 = new Person();
person1.name="Grag";
alert(person1.name);//"grag"---来自实例
alert(person2.name);//"Nicholas"--来自原型
delete person1.name;
alert(person1.name);//"Nicholas"--来自原型

通过使用hasOwnProperty()方法,可以检测一个属性是存在实例中,还是存在于原型中。

var person1 = new Person();
var person2 = new Person();
alert(person1.hasOwnProperty("name"));//false
alert(hasPrototypeProperty("person","name"));//true
person1.name="Grag";
alert(person1.name);//"grag"---来自实例
alert(person1.hasOwnProperty("name"));//true
alert(hasPrototypeProperty("person","name"));//false
alert(person2.name);//"Nicholas"--来自原型
alert(person2.hasOwnProperty("name"));//false
delete person1.name;
alert(person1.name)//"Nicholas"--来自原型
alert(person1.hasOwnProperty("name"));//false

更简单的原型写法

用一个包含所有属性和方法的对象字面量来重写整个原型对象

function Person(){}
Person.prototype = {
    constructor:Person,//由于字面量写法,导致constructor(构造函数的指针)不再指向Person了,所以我们需要特意将它设置适当的值
    name : "Nicholas",
    age : 29,
    job : "Software Engineer",
    sayName : function(){
        alert(this.name);
    }
}
var person1 = new Person();
alert(person1.name)//"Nicholas"

原型对象的问题

原型中所有属性是被很多实例共享的,这种共享对于函数非常合适。对于那些包含基本值的属性倒也说得过去,毕竟通过在实例上添加一个同名属性,可以隐藏原型中的对应属性。然而,对于包含引用类型值的属性来说,就有问题了---全部共享一个属性(无论怎样修改,其他实例的值都是一样的)

4.混合模式

构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性

function Person(name,age,job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ["Shelby","Court"];
}
Person.prototype = {
    constructor:Person,
    sayName:function(){
        alert(this.name);
    }
}
var person1 = new Person("Nicholas",29,"Software Engineer");
var person2 = new Person("Grag",27,"Doctor");
person1.friends.push("Van");
alert(person1.friends);//Shelby,Court,Van
alert(person2.friends);//Shelby,Court
alert(person1.friends === person2.friends);//false
alert(person1.sayName === person2.sayName);//true

这种构造函数与原型混成的模式,是目前在ECMAScript中使用最广泛,认同度最高的一种创建自定义类型的方法。可以说,这是用来定义引用类型的一种默认模式。

5.动态原型模式

function Person(name,age,job){
    //属性
    this.name = name;
    this.age = age;
    this.job = job;
    //方法
    if(typeof this.sayName != "function"){
        Person.prototype.sayName = function(){
            alert(this.name);
        }
    }
}
var friend = new Person("Nicholas",29,"Software Engineer");
friend.sayName();

这里只在sayName()方法不存在的情况下,才会将它添加到原型中。
使用动态原型模式时,不能使用对象字面量重写原型。

6.寄生构造函数模式

类似于工厂模式与构造函数模式结合体,自行查阅

7.稳妥构造函数模式

略,自行查阅

你可能感兴趣的:(JS 工厂模式、构造函数模式、原型模式、混合模式、动态原型模式,寄生构造函数模式,稳妥构造函数模式)