资讯专栏INFORMATION COLUMN

js面向对象浅析---对象创建的几种常见方式

Invoker / 2755人阅读

摘要:前言虽然使用构造函数或者使用对象字面量可以很方便的用来创建一个对象,但这种方式有一个明显的缺点使用一个接口创建多个对象会产生很多冗余的代码。即调用构造函数所创建的那个对象的原型对象好处是可以让所有对象的实例共享他的属性的方法。

前言

虽然使用Object构造函数或者使用对象字面量可以很方便的用来创建一个对象,但这种方式有一个明显的缺点:使用一个接口创建多个对象会产生很多冗余的代码。因此为了解决这个问题,人们开始使用以下几种方式来常见对象。

工厂模式

该模式抽象了创建对象的具体过程,用函数来以特定接口创建对象的细节

    function cPerson(name,sex,age){
    var o = new Object();
    o.name = name;
    o.sex = sex;
    o.age = age;
    o.show = function(){
        console.log(this.name,this.age,this.sex);
    }
    return o;
}
    var p1 = cPerson("谦龙","男","100");
        p1.show();
    var p2 = cPerson("雏田","女","14");
        p2.show();

工厂模式测试


工厂方式的问题:使用工厂模式能够创建一个包含所有信息的对象,可以无数次的调用的这个函数。虽然其解决了创建多个相似对象的问题,但却没有解决对象识别的问题(即如何得知一个对象的类型)

构造函数模式
function CPerson(name,sex,age) {//注意这里 构造函数首字母大写
    this.name = name;
    this.sex = sex;
    this.age = age;
    this.show = function () {
        console.log(this.name, this.age, this.sex);
    }
}


var p1 = new CPerson("谦龙","男","100");
    p1.show();
var p2 = new CPerson("雏田","女","14");
    p2.show();

构造函数模式测试

注意构造函数与工厂模式有些不同的地方,如下

构造函数首字母大写

没有显式地创建对象

将属性和方法赋值给了 this对象

没有return语句

而且以这种方式来调用构造函数会大致经历一下几个步骤

创建一个新的对象

将构造函数的作用域赋值给这个对象(因此this就指向了这个对象)

执行构造函数中的代码(即给新对象添加属性和方法的过程)

返回对象

注意:构造函数其实和普通的函数没有太大的差别,唯一的不同在于调用方式的不同。以下演示不同的几种调用方式

    // 调用方式1 new 方式
    
    var p1 = new CPerson("谦龙","男","100");
    p1.show();//谦龙 100 男
    
    // 调用方式2 普通函数调用
    
    CPerson("谦龙","男","100");
    window.show()//谦龙 100 男 注意属性和方法会被设置到window对象上
    
    // 调用方式3 在另一个对象的作用域中调用
    var obj = new Object();
        CPerson.call(obj,"谦龙","男","100");
        obj.show(); //谦龙 100 男 在obj的作用域

构造函数的问题:使用构造函数最主要的问题就是每个方法都要在每个实例上重新创建一次,p1与p2的都有show方法,但不是同一个Function的实例,因为function在js中也是一个对象。因此他们共有的show方法并不相等。

原型模式

每个函数都有一个prototype属性,这个属性是一个指针,指向一个对象。而这个对象的用途是 包含可以由特定类型的所有实例 共享的属性和方法。即调用构造函数所创建的那个对象的 原型对象

好处是可以让所有对象的实例共享他的属性的方法。即无需在构造函数中定义实例的信息

 function CPerson(){

    }
    CPerson.prototype.name="谦龙";
    CPerson.prototype.sex="男";
    CPerson.prototype.age=100;
    CPerson.prototype.show=function(){
        console.log(this.name, this.age, this.sex);
    }
    var p1 = new CPerson();
        p1.show(); //谦龙 100 男
    var p2 = new CPerson();
        p2.show();//谦龙 100 男
        console.log(p1.show == p2.show)//true

原型模式测试

由上图可知p1与p2共享属性和方法

原型模式的问题:

省略了为构造函数传递初始化参数,导致默认情况下所有实例将得到相同的属性值

所有属性都会被实例所共享,当属性的类型是引用类型的时候会出一定的问题,实例间对该属性的修改会相互影响
针对以上所说的第二个问题我们给出实例

        function CPerson(){

        }

        CPerson.prototype.name="谦龙";
        CPerson.prototype.sex="男";
        CPerson.prototype.age=100;
        CPerson.prototype.job=["前端","后端"];
        CPerson.prototype.show=function(){
            console.log(this.name, this.age, this.sex);
        }
        var p1 = new CPerson();
            p1.job.push("测试");
            console.log(p1.job);//["前端", "后端", "测试"]
        var p2 = new CPerson();
            console.log(p2.job);//["前端", "后端", "测试"]
            console.log(p1.job == p2.job);// true

测试

由以上可以看出,两个对象p1,p2对job的修改会相互影响,但按照正常思维,实例一般要有自己的全部的属性。

组合使用构造函数和原型模式

该方式利用构造函数定义实例属性、利用原型定义方法和共享的属性,结果每个实例都有一份实例属性的副本,而且共享着方法的引用,可谓是集两家之所长。

 function CPerson(name,sex,age) {//注意这里 构造函数首字母大写
         this.name = name;
         this.sex = sex;
         this.age = age;
         this.job=["前端","后端"];
     }

    CPerson.prototype={
        constructor:CPerson,//注意这里
        show : function () {
            console.log(this.name, this.age, this.sex);
        }
    }

    var p1 = new CPerson("谦龙","男",100);
    var p2 = new CPerson("雏田","女",20);
        p1.job.push("测试");
        console.log(p1.job);//["前端", "后端", "测试"]
        console.log(p2.job);//["前端", "后端"]
        console.log(p1.job == p2.job);//fasle
        console.log(p1.show == p2.show);//true

组合模式测试

说明:这种组合模式是使用最广泛、认同度最高的一种创建自定义类型的方法。

动态原型模式

动态原型模式将所有的信息都封装在了函数中,而通过构造函数中初始化原型,保持了同时使用构造函数和原型的优点

        function CPerson(name,sex,age) {//注意这里 构造函数首字母大写
            this.name = name;
            this.sex = sex;
            this.age = age;
            this.job=["前端","后端"];
            if(typeof this.show !="function"){ //注意这里 
                console.log("just one");
                CPerson.prototype.show=function(){
                    console.log(this.name, this.age, this.sex);
                }
            }
        }


        var p1 = new CPerson("谦龙","男",100); //just one
        var p2 = new CPerson("雏田","女",20);//没有输出

动态原型模式测试

寄生构造函数模式

该方式的基本思想是创建一个函数,用来封装创建对象的代码,然后再返回新创建的对象。构造函数在不返回值的情况下,默认会返回新对象的实例,而通过return语句可以修改调用构造函数时的返回值。

该方式有一定的应用场景比如,当我们想创建一个具有额外方法的数组而又不能修改Array构造函数的情况下,可以使用这种模式

 function MyOwnArray(){
        var arr=new Array();//创建新对象
            arr.push.apply(arr,arguments);
            arr.show=function(){
                console.log(this.join("|"));
            }
        return arr;
    }

    var arr1 = new MyOwnArray("谦龙","男",100);
        arr1.show();

寄生构造函数模式测试

稳妥构造函数模式

稳妥对象即没有公共属性,方法也不引用this对象,稳妥对象最适合在一些安全的环境中(例如禁止使用this和new)或者防止数据被其他应用程序修改的时候使用。

注意:稳妥构造函数和寄生式构造函数有许多类似的地方,以下是他们的不同之处

不使用new操作符来调用构造函数

创建对象的实例方法不使用this对象

  function CPerson(name,sex,age){
        var obj = new Object();
            // private members
        var myOwnName="谦龙";
        obj.showOwnName=function(){
            console.log(myOwnName);//只有通过该方法才能访问myOwnName 私有属性
        }
        obj.show=function(){
            console.log(name,sex,age);
        }
        return obj;
    }

    var p1=CPerson("谦龙","男","100");
        p1.show();
        p1.showOwnName();

稳妥构造函数模式测试

除了通过调用对应的方法来访问其数据成员,没有别的方法可以访问到原始添加的数据,其提供的这种安全机制适合在例如ADsafe等的环境下使用

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/86157.html

相关文章

  • 浅析前端上传

    摘要:项目上也用到很多上传文件的地方,七牛云,阿里云,讯飞上传都接触过,所以在这里做一个记录,总结一下前端上传的几种方式。类型的文件名七牛云上传浅析是一个基于七牛开发的前端。 showImg(https://segmentfault.com/img/bVbvibu?w=1920&h=1080); 图片,音频,视频等等这几种常见的资源类型,如果需要从前端上传到服务端,有几种方式呢?不妨回顾一下...

    terro 评论0 收藏0
  • js面向对象浅析---初识

    摘要:中的对象无序的属性的集合,属性可以包含基本值对象函数。共有四个描述其行为的特性。返回的是一个对象,如果是数据属性,则返回的属性有如果是访问器属性则返回的属性有对象遍历函数数据属性访问器属性测试 前言 基于类的对象:我们都知道面向对象的语言中有一个明显的标志,就是都有类的概念,通过类这个类似模板的东西我们可以创建许多个具有相同的属性和方法的对象。然而在ECMAScript中并没有类的概...

    evin2016 评论0 收藏0
  • js面向对象浅析--继承那些事

    摘要:有需要还可以修改指向谦龙寄生组合式继承思路是通过借用构造函数来继承属性,通过原型链的混合形式来继承方法改变执行环境实现继承有需要还可以修改指向谦龙谦龙拷贝继承该方法思路是将另外一个对象的属性和方法拷贝至另一个对象使用递归 前言 js中实现继承的方式只支持实现继承,即继承实际的方法,而实现继承主要是依靠原型链来完成的。 原型链式继承 该方式实现的本质是重写原型对象,代之以一个新类型的实例...

    molyzzx 评论0 收藏0
  • 前端基础汇总

    摘要:及相关问题数据类型函数中指向原型作用域闭包面向对象对象创建模式继承严格模式与对象转换的方法添加属性,根据原型创建区别新特性解构赋值简化对象写法剪头函数三点运算符模板字符串形参默认值异步过程深拷贝与浅拷贝赋值与浅拷贝的区别浅拷贝的几种方法实现 js及es相关问题 数据类型函数中this指向——————原型作用域闭包——————面向对象对象创建模式继承——————Es5严格模式Json与j...

    2json 评论0 收藏0
  • 前端基础汇总

    摘要:及相关问题数据类型函数中指向原型作用域闭包面向对象对象创建模式继承严格模式与对象转换的方法添加属性,根据原型创建区别新特性解构赋值简化对象写法剪头函数三点运算符模板字符串形参默认值异步过程深拷贝与浅拷贝赋值与浅拷贝的区别浅拷贝的几种方法实现 js及es相关问题 数据类型函数中this指向——————原型作用域闭包——————面向对象对象创建模式继承——————Es5严格模式Json与j...

    laznrbfe 评论0 收藏0

发表评论

0条评论

Invoker

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<