zoukankan      html  css  js  c++  java
  • Javascript对象创建

    一、概述

      虽然对象字面量可以用来创建对象,但在创建多个类似的对象时,不够优雅,不符合DRY原则。

    二、创建对象

      有以下几种模式:

      1.工厂模式

      2.构造函数模式

      3.原型模式

      4.组合构造函数和原型模式(推荐)

    5.动态原型模式 (推荐)

    6.稳妥构造函数模式 

      1.工厂模式  

    function createPerson(name,age,job)
            {
                var o={
                    name:name,
                    age:age,
                    job:job,
                    saySelf:function(){
                        console.log(this.name+this.age+this.job);
                    }
                };
                return o;
            }
            var person=createPerson("我是工厂模式建的",20,"ape");
            person.saySelf();

    优点:可创建多个相似对象。

    缺点:无法识别对象。

     

     

    2.构造函数模式

      

    function Person(name,age,job)
            {
                this.name=name;
                this.age=age;
                this.job=job;
                this.saySelf=function(){
                    console.log(this.name+this.age+this.job);
                }
            }
            var person=new Person("构造函数模式",20,"ape");
            person.saySelf();

        特点:

      1. 没有显式的创建对象,直接将属性和方法给了this;
      2. 没有return;
      3. 函数名大写,一般构造函数名大写;      

        要创建Person的实例,必须使用new操作符,Person的实例都有constructor属性,该属性指向Person();

        

            console.log(person.constructor===Person)//true
            console.log(person instanceof Person) //true 推荐

        自定义构造函数可以标识为一种特定类型。

        任何函数,只要通过new调用,就可以当作构造函数,构造函数与普通函数没什么两样。

        优点:可识别类型。

        缺点:每个方法要在每个实例上重建一遍,工厂模式也有此类问题。

    console.log(person.saySelf===person2.saySelf);//false

      3.原型模式

        

        (function(){
            function Person()
            {
            }
            Person.prototype.name='原型模式';
            Person.prototype.age='28';
            Person.prototype.job='Ape';
            Person.prototype.saySelf=function(count){
                if(count)
                console.log(count+":"+this.name+this.age+this.job);
                else
                  console.log(this.name+this.age+this.job);
            }
            var person=new Person();
            var person2=new Person();
            person.saySelf();
            person2.saySelf();
            console.log(1,person.saySelf===person2.saySelf);//true
            console.log(2,Person.prototype.isPrototypeOf(person));//true
            console.log(3,Object.prototype.isPrototypeOf(person));//true
            console.log(4,Object.getPrototypeOf(person)===Person.prototype);//true
            console.log(8,person.name);
            person.name="看看变不变";
            person.saySelf(9);//9:看看变不变28Ape
            person2.saySelf(10);//10:原型模式28Ape
    delete person.name; person.saySelf(11);//11:原型模式28Ape person.__proto__.name="现在肯定变了"; person2.saySelf();//现在肯定变了28Ape 只在Firefox、Safari、Chrome中有效 })();

    当添加一个属性时,这个属性就会屏蔽原型对象的同名属性。但是可以通过delete删除实例属性,让实例重新可以访问这个属性。说话是苍白的,看上面代码。

    通过hasOwnProperty()可判断属性是否是实例自己的属性(区别于从原型上继承来的)。

     

            console.log(person.hasOwnProperty("name"));//true
            delete person.name;
            console.log(person.hasOwnProperty("name"));//false

    那么,怎么检测某个属性是否是实例的属性呢,用in操作符,无论属性在实例中还是在原型中,都返回true

     

            console.log("in","name" in person);//true
            delete person.name;
            console.log("in","name" in person);//true

         可用Object.keys()方法,返加一个所有可枚举属性的的字符串数组。

        如果想得到,全部的属性可用Object.getOwnPropertyNames();

        两个方法的共同点:均列举出自有属性,不查找原型链;

               不同点:Object.keys()方法返回可枚举属性,Object.getOwnPropertyNames()返回所有属性的keys。

            person2.sex="男";
            console.log(Object.keys(Person.prototype).join(";"));//name;age;job;saySelf
            console.log(Object.getOwnPropertyNames(Person.prototype).join(";"));//constructor;name;age;job;saySelf
            console.log(Object.keys(person2).join(";"));//sex
            console.log(Object.getOwnPropertyNames(person2).join(";"));//sex

        原型的动态性,这个很好理解,原型只是引用用,动态添加,当然可用。

        但是,实例化一个对象后,再去重写一个原型,实例仍然指向原来的原型。

     //原型的动态性
        (function(){
            function Person()
            {
            }
            Person.prototype.name='原型模式';
            Person.prototype.age='28';
            Person.prototype.job='Ape';
            Person.prototype.saySelf=function(count){
                if(count)
                    console.log(count+":"+this.name+this.age+this.job);
                else
                    console.log(this.name+this.age+this.job);
            }
            var person=new Person();
            console.log(Object.getOwnPropertyNames(person.__proto__).join(";"));
            Person.prototype={
                constructor:Person,
                sex:"汉子"
            }
            var person2=new Person();
            console.log(Object.getOwnPropertyNames(person.__proto__).join(";"));
            console.log(Object.getOwnPropertyNames(person2.__proto__).join(";"));
        })();
    View Code

      

      优点:共享方法,可用isPrototypeOf检测是否是原型,在ES5中,可用getPrototypeOf得到原型。

      缺点:不能拥有自己的属性。这个致命的缺点导致基本没有人用原型模式。

     

     

    4.组合构造函数和原型模式。

     

    function Person(name,age,job)
            {
                this.name=name;
                this.age=age;
                this.job=job;
            }
            Person.prototype={
                constructor:Person,
                saySelf:function()
                {
                    console.log(this.name+this.age+this.job);
                 }
            };
            Person.static=function()
            {
                console.log("这是一个静态方法");
            }
            var person=new Person();
            Person.static();//这是一个静态方法
            person.static();//Uncaught TypeError: undefined is not a function

         这个模式解决了以上所有的缺点,同时具有以上所有的优点,是在javascript应用最广泛的创建自己定义类型的方法。是用来定义定义引用类型的一种默认模式。

      5.动态原型模式 

        //动态原型模式
        (function(){
            function Person(name,age,job)
            {
                this.name=name;
                this.age=age;
                this.job=job;
                if(typeof this.saySelf!=="function") {
                    Person.prototype.saySelf = function ()
                    {
                        console.log(this.name + this.age + this.job);
                    }
             
                }
            }
    
            var person=new Person("工厂模式",20,"frontEndpe");
            var person2=new Person("工厂模式Ac",20,"frontEndApe");
            person.saySelf();
            person2.saySelf();
        })();

    优点:把原型封装构造函数中。

    缺点:每个实例化都进行一次判断(这个也不算什么)。

      6.稳妥构造函数模式  

        //稳妥构造函数模式
        (function(){
            function Person(name)
            {
                var o={};
                //可以添加私有的方法和变量
                o.sayName=function()
                {
                    console.log(name);
                }
                return o;
            }
    
            var person=Person("工厂模式");
            var person2=Person("工厂模式Ac");
            person.sayName();
            person2.sayName();
            var say=person2.sayName;
            say();
    
        })();

    稳妥对象:没有公共属性的对象。

    name属性只有sayName()闭包访问

    三、总结

      综合以上,推荐使用 4.组合构造函数和原型模式和5.动态原型模式。

      它们都有以下优点:

      1.都可以识别对象 。

      2.都可以有自己的属性值(constructor) 和共享的属性(prototype)

    四、代码

     

     

    <!DOCTYPE html>
    <html>
    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
    <script>
    "use strict";
    (function(){
        // 工厂模式
        (function(){
            function createPerson(name,age,job)
            {
                var o={
                    name:name,
                    age:age,
                    job:job,
                    saySelf:function(){
                        console.log(this.name+this.age+this.job);
                    }
                };
                return o;
            }
            var person=createPerson("工厂模式",20,"ape");
            var person2=createPerson("工厂模式2",20,"ape");
            console.log(person.saySelf===person2.saySelf);
            person.saySelf();
        });//();
        // 构造函数模式
        (function(){
            function Person(name,age,job)
            {
                this.name=name;
                this.age=age;
                this.job=job;
                this.saySelf=function(){
                    console.log(this.name+this.age+this.job);
                }
            }
            var person=new Person("构造函数模式",20,"ape");
            var person2=new Person("构造函数模式2",20,"ape");
            person.saySelf();
            console.log(person.constructor===Person);//true
            console.log(person instanceof Person); //true 推荐
            console.log(person.saySelf===person2.saySelf);//false
        });//();
        //原型模式
        (function(){
            function Person()
            {
            }
            Person.prototype.name='原型模式';
            Person.prototype.age='28';
            Person.prototype.job='Ape';
            Person.prototype.saySelf=function(count){
                if(count)
                console.log(count+":"+this.name+this.age+this.job);
                else
                  console.log(this.name+this.age+this.job);
            }
            var person=new Person();
            var person2=new Person();
            person.saySelf();
            person2.saySelf();
            console.log(1,person.saySelf===person2.saySelf);//true
            console.log(2,Person.prototype.isPrototypeOf(person));//true
            console.log(3,Object.prototype.isPrototypeOf(person));//true
            console.log(4,Object.getPrototypeOf(person)===Person.prototype);//true
            console.log(5,person.name);
            person.name="看看变不变";
            person.saySelf(9);//9:看看变不变28Ape
            person2.saySelf(10);//10:原型模式28Ape
            console.log(person.hasOwnProperty("name"));//true
            console.log("in","name" in person);//true
            delete person.name;
            console.log("in","name" in person);//true
            console.log(person.hasOwnProperty("name"));//false
            person.saySelf(11);//11:原型模式28Ape
            person.__proto__.name="现在肯定变了";
            person2.saySelf();//现在肯定变了28Ape  只在Firefox、Safari、Chrome中有效
            person2.sex="男";
            console.log(Object.keys(Person.prototype).join(";"));//name;age;job;saySelf
            console.log(Object.getOwnPropertyNames(Person.prototype).join(";"));//constructor;name;age;job;saySelf
            console.log(Object.keys(person2).join(";"));//sex
            console.log(Object.getOwnPropertyNames(person2).join(";"));//sex
        });//();
        //原型的动态性
        (function(){
            function Person()
            {
            }
            Person.prototype.name='原型模式';
            Person.prototype.age='28';
            Person.prototype.job='Ape';
            Person.prototype.saySelf=function(count){
                if(count)
                    console.log(count+":"+this.name+this.age+this.job);
                else
                    console.log(this.name+this.age+this.job);
            }
            var person=new Person();
            console.log(Object.getOwnPropertyNames(person.__proto__).join(";"));
            Person.prototype={
                constructor:Person,
                sex:"汉子"
            }
            var person2=new Person();
            console.log(Object.getOwnPropertyNames(person.__proto__).join(";"));
            console.log(Object.getOwnPropertyNames(person2.__proto__).join(";"));
        });//();
        //组合构造函数和原型模式。 最常用
        (function(){
            function Person(name,age,job)
            {
                this.name=name;
                this.age=age;
                this.job=job;
            }
            Person.prototype={
                constructor:Person,
                saySelf:function()
                {
                    console.log(this.name+this.age+this.job);
                 }
            };
            Person.static=function()
            {
                console.log("这是一个静态方法");
            }
            var person=new Person();
            Person.static();//这是一个静态方法
            person.static();//Uncaught TypeError: undefined is not a function
        });//();
        //动态原型模式
        (function(){
            function Person(name,age,job)
            {
                this.name=name;
                this.age=age;
                this.job=job;
                if(typeof this.saySelf!=="function") {
                    Person.prototype.saySelf = function ()
                    {
                        console.log(this.name + this.age + this.job);
                    }
    
                }
            }
    
            var person=new Person("工厂模式",20,"frontEndpe");
            var person2=new Person("工厂模式Ac",20,"frontEndApe");
            person.saySelf();
            person2.saySelf();
        });//();
        //稳妥构造函数模式
        (function(){
            function Person(name)
            {
                var o={};
                //可以添加私有的方法和变量
                o.sayName=function()
                {
                    console.log(name);
                }
                return o;
            }
    
            var person=Person("工厂模式");
            var person2=Person("工厂模式Ac");
            person.sayName();
            person2.sayName();
            var say=person2.sayName;
            say();
        });//();
    })();
    </script>
    </body>
    </html>
    View Code

     

  • 相关阅读:
    20160205.CCPP体系详解(0015天)
    盘点各专业到古代都能干些啥
    一份简单的在 Linux下编译及调试 C 代码的指南
    WordPress Gravatar国内加载缓慢解决办法
    linux修改mysql字符集编码
    阿里合伙人邵晓锋:什么是创业者应该抵制的诱惑?
    6月27日云栖精选夜读:细数智能家居的痛点
    6月26日云栖精选夜读:成为一名Java高级工程师你需要学什么
    搭建百万级别邮件发送平台
    黑科技实验室:这些高级装备厉害了!
  • 原文地址:https://www.cnblogs.com/etoah/p/4114701.html
Copyright © 2011-2022 走看看