【js基础】创建对象&函数的六种模式

*为更加清晰的了解原生JavaScript中的创建对象&函数,本文均采用ES5的语法。 

一、最简单的创建对象

1.使用new关键字创建Object

var student = new Object;

student.id = 12345;

student.name = "xiaoming";

student.sex = "male";

student.word = function() {

    alert("I am Xiaoming!")

}

2.对象字面量

var student = {

    id: 12345,

    name: "xiaoming",

    sex: "male",

    word: function() {

        alert("I am Xiaoming!")

    }

}

上面的两种方式,会产生大量的代码,而且没有复用性。由此,我们可以考虑采用工厂模式,即类似于工厂用一条流水线,批量生产的方式创建对象:

二、工厂模式

function createStudent(name,sex,id) {

    var o = new Object();

    o.name = name;

    o.sex = sex;

    o.id = id;

    o.word = function(){

        alert(this.name);

    }

    return o;

}

上面定义的函数createStudent,就是使用工厂模式的方式创建对象的。每次调用函数时,新建一个对象并给其属性赋值。

var student1 = createStudent("xiaoming", "male", 12345);

var student2 = createStudent("xiaoling", "female", 54321)

和直接创建对象相比,工厂模式大大节省了代码量,并且可复用,解决了重复实例化多个对象的问题。但同时也有一定的弊端:没有解决对象识别的问题。在JavaScript中,对象还包括Date、Array等特殊对象,仅通过工厂模式无法解决对象类型的识别。由此,我们可以采用构造函数:

三、构造函数模式

function Student(name,sex,hobby)  {

    this.name = name;

    this.sex = sex;

    this.hobby = hobby;

    this.word = function(){

        alert(this.name);

    }

}

以此方法调用构造函数步骤 {

1、创建一个新对象

2、将构造函数的作用域赋给新对象(将this指向这个新对象)

3、执行构造函数代码(为这个新对象添加属性)

4、返回新对象

}

//调用并生成对象

var student1 = new Student ("xiaoming", "male", ["singing", "soccer", "game"]);

var student2 = new Student ("xiaoling", "female", ["comic", "dancing", "reading"]);

console.log(student1 instanceof Object);  //true

console.log(student1 instanceof Student);  //true

console.log(student2 instanceof Object);  //true

console.log(student2 instanceof  Student );  //true

console.log(student1.constructor);   //constructor 属性返回对创建此对象的数组、函数的引用

instanceof运算符用于测试构造函数的prototype属性是否出现在对象的原型链中的任何位置。由上例可以看出,通过构造函数创建的student1、student2既是Student的实例,也是Object的实例。这说明通过构造函数创建的对象是可以判断其对象类型的。

构造函数对比工厂模式有以下不同之处:

1、没有显式地创建对象

2、直接将属性和方法赋给了 this 对象

3、没有 return 语句

构造函数依然存在一些问题。虽然不再重复的显式创建对象,但是每次new一个Student时,其实也是每次都创建了一个Function。而Function也是对象的一种类型。其本质是多次创建了函数。为解决这个问题,产生了原型模式。

四、原型模式

function Student() {

}

Student.prototype.name = "xiaoming";

Student.prototype.sex = "male";

Student.prototype.hobby= ["singing", "soccer", "game"];

Student.prototype.word = function(){

    alert(this.name);

};

由上面代码可以看出,Student的属性定义在了它的原型(prototype)上。这样的方式可以使得Student所有对象实例共享它的属性和方法,无需在每次创建对象时都要创建一份新的属性和方法,直接定义属性和方法在对象的原型上,可以使得所有实例都直接继承。

console.log(Student.prototype);  //Object{name: 'xiaoming', sex: "male", hobby: Array[3]}

var student1 = new Person();        //创建一个实例person1

console.log(student1.name);        //xiaoming

student1.name = "xiaojun";

console.log(student1.name);        // xiaojun

上文可以看出,在实例上再次定义同名的属性(私有属性),可以覆盖其原型上的公有属性。

五、组合模式(构造函数模式+原型模式)

单纯的构造函数和原型模式各有优缺点。因此,我们可以利用构造函数模式定义实例属性,原型模式用于定义方法和共享的属性,结合两者的优点使用。

//构造函数定义属性:

function Student(name,sex,hobby){

    this.name = name;

    this.sex= sex;

    this.hobby= hobby;

}

//原型定义方法:

Student.prototype = {

    constructor: Student,  //让构造器指向自身

    word: function(){

        alert(this.name);

    }

}

var student1 = new Student("xiaoming","male",["singing", "soccer", "game"]);

console.log(student1);

上面代码中的constructor的意思是,每个函数都有prototype属性,指向该函数原型对象,原型对象都有constructor属性,是一个指向prototype属性所在函数的指针。具体对面向对象的constructor的解读,可看文章连接:https://www.jianshu.com/p/49e5e848fee0

在其他面向对象的语言中,属性和方法往往是封装在一起的,而在组合模式中,构造函数和原型是分开定义了属性和方法的,所以并没有真正意义上的封装,因此,动态原型模式正是解决这一问题的方案。

六、动态原型模式

动态原型模式是将属性和方法都封装在构造函数中(包括原型属性和实例属性),通过在构造函数中实例化原型(仅在必要的情况下)实现封装,又保持了同时使用构造函数和原型的优点。其本质是在构造函数中加了一层对于方法的判断,从而实现动态生成原型上的方法。

function Student(name,sex,hobby){

        this.name = name;

        this.sex = sex;

        this.hobby = hobby;

        if(typeof this.word != "function") {//这段判断语句的作用是限制Person.prototype属性(原型属性对象)只生成一次,要不然每次实例化一个Person对象都会去写一遍原型对象

            Student.prototype.word = function () {

                alert(this.name);

            }

        }

    }

    var student1 = new Student("xiaoming","male",["singing", "soccer", "game"]);

创建Student构造函数时,会创建一个prototype属性,该属性实际上就是Student.prototype的原型对象,prototype属性是一个指针,指向Person.prototype的原型对象,

当this指向的属性非方法(typeof this.word != "function"),则在当前对象的原型上创建一个新方法。避免了重复修改原型方法。

你可能感兴趣的:(【js基础】创建对象&函数的六种模式)