zoukankan      html  css  js  c++  java
  • Javascript 中定义对象的几种方式

    Javascript 中定义对象的几种方式.

    方式1:基于已有对象(obj) 扩充其属性和方法

    js 中没有类的概念,只有对象。

    <script type="text/javascript">
        var obj = new Object();
        obj.name = "zhangsan"; //定义一个属性
        obj.sayName = function (name)//定义一个方法
        {
            this.name = name;
            alert (this.name);
        }
        obj.sayName("lisi");
    </script>

    弊端:

    对象只有一个(只有一个 obj),如果再想要一个只能在来一个 obj2

    方式2: 工厂方式创建对象

    类似于 java 中的静态方法。调用一个就new出来一个对象。

    <script type="text/javascript">
        //工厂方式创建对象
        
        function createObject()
        {
            var obj = new Object();
            
            obj.username = "zhangsan";
            obj.password = "123";
        
            obj.get = function ()
            {
                alert (this.username + ", " + this.password);
            }
            return obj;    
        }
        var obj1 = createObject(); //通过调用工厂方法 createObject()创建第一个对象。
        var obj2 = createObject(); //通过调用工厂方法 createObject()创建第二个对象。
        obj1.get();
        obj2.get();
    </script>

    结果:创建出来了2个对象

    但是我们注意到上面把 username passwword 写死了。稍微改一下:

    <script type="text/javascript">
        //工厂方式创建对象
        
        function createObject(username, password)
        {
            var obj = new Object();
            
            obj.username = username;
            obj.password = password;
        
            obj.get = function ()
            {
                alert (this.username + ", " + this.password);
            }
            return obj;    
        }
        var obj1 = createObject("allen","qqq"); //通过调用工厂方法 createObject()创建第一个对象。
        var obj2 = createObject("jenny", "ooo"); //通过调用工厂方法 createObject()创建第二个对象。
        obj1.get();
        obj2.get();
    </script>

    结果:打印出 allen,qqq                   jenny,ooo

    但是我们仍然觉得可以改进。我们注意看,上面的 obj.get 函数是定义在 createObject()中的。也就是说任何调用 createObject() 方法创建对象的时候,都要在内存中给 obj.get() 函数一个空间。这样明显很浪费。

    最好的方式是只要多次调用 createOjbect() 就可以创建出多个对象。而这些对象在内存中共享一份 get() 函数代码。

    我们可以改一下,把 get() 放在外面。如下:

    <script type="text/javascript">
        //工厂方式创建对象
        function createObject(username, password)
        {
            var obj = new Object();
            
            obj.username = username;
            obj.password = password;
        
            obj.get = get;
            return obj;
        }
        function get()
        {
            alert (this.username + ", " + this.password);
        }
        
        var obj1 = createObject("allen","qqq"); //通过调用工厂方法 createObject()创建第一个对象。
        var obj2 = createObject("jenny", "ooo"); //通过调用工厂方法 createObject()创建第二个对象。
        
        obj1.get();
        obj2.get();
    </script>

     那么最后这种做法是比较好的做法:让一个函数 被多个对象所共享,而不是每一个对象拥有一个函数对象。

    当然也有一个潜在问题,就是一般我们希望属性和方法等都定义在一起,但是现在分开了。但这个没有解决方式。

    3。 构造函数方式:

    <script type="text/javascript">
        //构造函数方式创建对象
        function Person()//这是一个构造函数
        {
            //如果我们用new的方式,那么在执行第一行代码之前,js引擎会为我们生成一个对象
            this.username = "zhangsan";
            this.password = "qqq";
            
            this.getInfo = function()
            {
                alert(this.username + ", " + this.password);
            }
          //这里有一个隐藏的 return 语句, 用于将之前生成的对象返回。所以不需要显示的 return }
    var person = new Person(); person.getInfo(); </script>

    我们看,过去我们利用 createObject()创建对象的时候,代码中要return obj;

    但是我们现在这个构造函数方法没有 return。而是利用了隐式的 return。

    我们继续改一下,不把 username password hard code.

    <script type="text/javascript">
        //构造函数方式创建对象
        function Person(username, password)
        {
            //如果我们用new的方式,那么在执行第一行代码之前,js引擎会为我们生成一个对象
            this.username = username;
            this.password = password;
            
            this.getInfo = function()
            {
                alert(this.username + ", " + this.password);
            }
            //这里有一个隐藏的 return 语句, 用于将之前生成的对象返回。所以不需要显示的 return
        }
        
        var person = new Person("user", "passwd");
        person.getInfo();
    </script>

    这个方法可以在构造对象的时候传递参数。

    方式4:原型(prototype)方式

        <script type="text/javascript">
            //使用原型(prototype)方式创建对象
            function Person()
            {
            }
            Person.prototype.username = "zhangsan"; //给 Person 的原型附加属性
            Person.prototype.password = "qqq";
            Person.prototype.getInfo = function()
            {
                alert(this.username + ", " + this.password);
            }
            
            var person = new Person();
            var person2 = new Person();
            person.username = "lisi"; //修改 person对象的 username 值
            person.getInfo();
            person2.getInfo();

    结果:

    zhangsan, qqq

    lisi, qqq

    单纯使用 prototype 方式有2个问题:

    1. 无法在构造函数中通过传参数为属性赋初值,只能在对象生成后再后续修改属性值。

    2. 容易导致程序错误。

    为什么容易导致程序错误?我们把code改一下, 把 username 变成 array

        <script type="text/javascript">
            //使用原型(prototype)方式创建对象
            function Person()
            {
                
            }
            Person.prototype.username = new Array("mary"); //username 变成 Array初始值 Mary
            Person.prototype.password = "123";
            Person.prototype.getInfo = function()
            {
                alert(this.username + ", " + this.password);
            }
            
            var person = new Person();
            var person2 = new Person();
            person.username.push("zhangsan");
            person.username.push("lisi");
            person.password = "456";
            person.getInfo();
            person2.getInfo(); //注意,这里我们没有对 person2 的属性进行修改
        </script>

    我们注意,上面的程序只对 person 进行了属性修改, 没有对 person2对象更改属性,那么结果是不是应该是

    mary, zhangsan, lisi, 456

    mary, 123

    但结果却是:

    mary, zhangsan, lisi,456

    mary, zhangsan, lisi, 123

    奇怪,为什么没有改 person2 的 username, 它却也变成和person一样了呢?这是为什么呢?

    这是因为我们是通过原型创建的对象,他们的属性值只有一份,是共享给 person 和 person2 的。

    注意,这里 username 是 Array, Array是引用型的数据类型; password 是 string, string是常量型的数据类型。

    当 person 对象更改 username 的时候,由于 Array是引用型的,所以不会创建新的 Array,仅仅是把内容变化了。

    而当 person 对象更改 password 的时候,由于 String 是常量型的,所以会创建出一个新的 String 出来让 person去指向。而 person2仍然在指向原来的 String。

    因此,我们看到在结果中 person 和 person2的 username 都相同,而 password各自指向自己的。

     总结一下就是:如果使用原型方法生成对象, 那么生成的所有对象会共享原型中的属性, 这样如果一个对象更改了属性,那么也会反映到其他对象中。

     4. 使用原型+构造函数的方式来定义对象

    前面我们看到如果使用纯原型的方式生成对象,那么所有生成对象都会共享圆形中的一份属性,这样显然不太好。因为我们希望的是不同的对象有不同的属性,但是方法是一样的用一份就行了。那么怎么办呢?我们使用原型+构造函数的方法。

    <html>
    <head>
    <script type="text/javascript">
        function Person() {
            this.username = new Array();
            this.password = "123";
        }
        Person.prototype.getInfo = function() {
            alert(this.username + ", " + this.password);
        }
        var p = new Person();
        var p2 = new Person();
    
        p.username.push("zhangsan");
        p2.username.push("lisi");
    
        p.getInfo();
        p2.getInfo();
    </script>
    </head>
    <body>
    </body>
    </html>

    结果:

    zhangsan, 123

    lisi, 123

    当然你可以给这种方式传递参数

    5. 动态原型方式

     那么我们看上面的方式 getInfo() 函数只能写在构造函数外面。我们是否能够写在里面,但是仍然该方法只被调用一次,即不会每个对象都要有一份浪费内存空间?

    我们可以这样:

    <html>
    <head>
    <script type="text/javascript">
        function Person(username, password) {
            this.username = username;
            this.password = password;
        
            if (typeof Person.flag == "undefined")
            {
                alert("invoked"); //判断是否确实只被执行了一次。
                Person.prototype.getInfo = function() {
                    alert(this.username + ", " + this.password);
                }
                Person.flag = true;
            }
            
        }
        var p = new Person("zhangsan", "qqq");
        var p2 = new Person("lisi", "ff");
    
        p.getInfo();
        p2.getInfo();
    </script>
    </head>
    <body>
    </body>
    </html>

    结果:一次弹出

    invoked

    zhangsan, qqq

    lisi, ff

    动态原型方式:在构造体中通过标帜量让所有对象共享一个方法,而每个对象拥有自己的属性。

  • 相关阅读:
    jmeter_分布式测试
    Locust性能测试_百度案例
    tkinter学习笔记_06
    tkinter学习笔记_05
    web前后端交互,nodejs
    Chrome Vue Devtools插件安装和使用
    line-height和height的区别
    网站头部导航
    屏蔽元素默认样式中的边距
    CSS Float(浮动)
  • 原文地址:https://www.cnblogs.com/backpacker/p/2619203.html
Copyright © 2011-2022 走看看