zoukankan      html  css  js  c++  java
  • JavaScript 对象 之创建对象 学习笔记

      假设我们有这样的一个需求:记录一个人的 名字和年龄,然后有个方法可以显示这个人的名字和年龄。

      按照普通的方法,我们的代码应该是这样的:

      

    var person1 = new Object() ,
        person2 = new Object() ;
    
    person1.name = "TOM" ;
    person1.age = 18 ;
    person1.show = function () {
        alert ("Name:" + this.name + " ; Age:" + this.age);        
    }
    person2.name = "LiLei" ;
    person2.age = 22 ;
    person2.show = function () {
        alert ("Name:" + this.name + " ; Age:" + this.age);        
    }

      

      以上的写法虽然能解决了该需求,但是却很坑爹,因为出现了大量的重复代码。让码农处于一种毫无意义的重复工作中。

      为了解决这些问题,人们开始了换一种新的方式去解决这个问题。


    一、工厂模式

      

    function createperson(name,age) {
        o = new Object() ;
        o.name = name ;
        o.age = age ;
        o.show = function(){
            alert("Name:" + this.name + " ;Age:" +this.age);
        }
        return o;
    }
        var person1 = createperson("TOM",18);
        var person2 = createperson("LiLei",20);

       这个模式虽然解决了之前的创建多个对象所引发的重复代码的问题,但是没有解决对象识别的问题。即,这个对象的类型到底是啥。


    二、构造函数模式

      

    function Person(name,age){
        this.name = name ;
        this.age = age ;
        this.show = function() {
            alert("Name:" + this.name + " ;Age:" + this.age);
        };
    }
    
    var person1 = new Person("Tom",18);
    var person2 = new Person("LiLei",20);

      构造函数 始终以 一个大写字母为开头 如 Person()。

      创建的对象,可以使用 constructor 属性 可以发现该属性 指向 Person。

      但是,这种方式并没有缺点。 person1 和 person2 都享有同样的方法,即 show(), 这里却 实例化 了两次。这对内存管理造成了极大的浪费。因此,我们可以稍微改动下该函数。

    function Person(name,age) {
        this.name = name ;
        this.age = age;
        this.show = show();
    }
    
    //创建一个全局函数
    function show() {
        alert("Name:" + this.name + " ;Age:" + this.age);
    }
    
    var person1 = new Person("Tom",18);
    var person2 = new Person("LiLei",20);

      这样,person1 和 person2 就可以享有同样的方法 show(), 而不需要实例化两次。

      可是这样还是不够的,创建了全局函数,会导致别人可能在其他地方重写了这个功能,降低了对象的封装性


    三、原型模式

    function Person() {
    
    }
    var friends = new Person();
    

    Person.prototype.friends = ['Lucy'] ;
    // 切断了构造函数和原型之间的联系。 所以 friends 访问不到这里面的值,也没有这些属性。 Person.prototype = { name : "Tom", age : 18, show : function() { alert("Name:" + this.name + " Age:" + this.age); } } //只是在原型上添加了 friends 所以 friends 能访问到这个值 Person.prototype.friends = ['Lucy','Lily'] ; var person1 = new Person(); var person2 = new Person(); person2.name = "LiLei"; // person2 的 name 为 LiLei person1.name = "HanMei"; //person1的 name 为 HanMei delete person1.name; //person1 的 name 又变为 prototype(原型) 里的 name 即 Tom //以上可以解释 实例属性 和 原型属性 的关系 //即 当 有 实例属性时, 访问对象属性时,访问到的属性为实例,否则,访问原型里的属性。 alert( friends.friends ) //返回 ['Lucy'] ; 因为 已经为 Person 的原型 新增了 属性 friends。 alert( friends.name ) //返回 错误。 而之后的 原型 直接整个都被重写了,所以friends 不能访问到之后的属性。 person1.friends.push("Jim"); alert( person1.friends ); //返回 ['Lucy','Lily',"Jim"] alert( person2.friends ); //返回 ['Lucy','Lily',"Jim"] // 因为 Person 的原型 friends 指向 ['Lucy','Lily'] 该数组, // Person1 也是同样指向该数组,对该数组操作, 会直接修改 该数组。 // 从而导致 Person2.friends 也会改变。 // 这并不是我们所需要的,所以这是一个错误!

       原型模式 解决了构造函数模式 所不能解决的问题,但是也可能会出现像上述这种并不想看到的错误。因此出现了,我们可以把这两种模式组合起来,来满足我们的要求。


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

      

    function Person(name,age) {
        this.name = name ;
        this.age = age ;
        this.friends = [ "Lucy","Lily" ];
    }
    
    Person.prototype = {
        constructor:Person,
        show:function(){
            alert( "Name:" + this.name + " ;Age:" + this.age );
        }
    }
    
    var person1 = new Person("Tom",18);
    var person2 = new Person("LiLei",20);
    
    person1.friends.push("Jim");
    
    alert(person1.friends);  //  返回 ["Lucy","Lily","Jim"]    
    alert(person2.friends);  //  返回 ["Lucy","Lily"]

      将所有的实例属性都放在 构造函数 中声明,所有实例共享的属性 和 方法 都在原型中定义。

      构造函数和原型模式的混合使用,是目前 使用最广泛、认同度最高的方法。


     五、动态原型模式

      

    function Person(name,age){
        this.name = name;
        this.age = age;
        
        if (typeof this.show != "function") {
            
            Person.prototype.show = function () {
                alert("Name" + this.name + " ;Age:" + this.age);
            }
        }
    }
    
    var person1 = new Person("Tom",18);
    //  当 Person 第一次 实例化的时候,函数内部自动执行生成了 原型 show()
    
    var person2 = new Person("LiLei",20);
    person2.show();    
    //  第一次实例化的时候已经生成 原型 show() 因此, person2 能直接调用;

      这种可以把 所有的信息 (包括属性和方法)  全部都集中在一个构造函数里。

      从视觉上看,可以一目了然,能在一个构造函数里 看到所有的属性和方法,方便以后修改等。。。


    六、寄生构造函数模式

    function Person(name,age) {
        var o = new Object() ;
        o.name = name ;
        o.age = age ;
        o.show = function () {
            alert("Name:" + this.name + " ;Age:" + this.age) ;
        };
        
        return o;
    }
    
    function SpecialPerson(name,age) {
      var o = new Person(name,age) ;
      o.showage = function () {
        alert (this.age);
      };
      
      return o;
    }

    var person1 = new Person("Tom",18);
    var person2 = new Person("LiLei",20);

    person1.showage()  // 18
    person2.showage()  // ERROR

      除了 最后的 new 外,剩下的几乎跟工厂模式一模一样!

      当我们遇到一个不能直接修改的构造函数时, 可以创建另一个函数 去寄生到这个构造函数上,来添加原本没有的功能。


    七、稳妥构造函数模式

    function Person(name,age) {
        var o = new Object() ;
        
        o.show = function () {
            alert("Name:" + name + " ;Age:" + age);
        }
        
        return o;
    }
    
    var person1 = Person("Tom",18);
    person1.show();

      当 当前的环境不允许使用 new 和 this. 只能通过 内定的几种方法来获取值。没有别的办法从外部将 值 传入 构造函数 里,提供了一种安全性。适合在安全环境下使用。

  • 相关阅读:
    SQL server 数据库安装
    jmeter接口测试
    jmeter测试之-脚本制作
    HTTP协议
    计算机原理
    Ubuntu 14.04 搭建 LNMP
    pycharm使用技巧
    hihoCoder #1867 GCD
    Mail.Ru Cup 2018 Round 2 Problem C Lucky Days
    C++ Essentials 之 lower_bound 和 upper_bound 的比较函数格式不同
  • 原文地址:https://www.cnblogs.com/linjilei/p/5118207.html
Copyright © 2011-2022 走看看