創建對象的常用四種模式和優缺點


一、工廠模式

        function createCar(color,type){
            var car = new Object();
            car.color = color;
            car.type = type;
            car.sayColor = function(){
                alert(this.color);
            };
            return car;
        }
        var car1 = createCar('red','CDV');
        var car2 = createCar('blue','SUV');
        car1.sayColor();  //red
        car2.sayColor();  //blue
        console.log(car1);
        console.log(car2);

  運行結果:

  1.  特點:用函數來封裝創建對象的細節,內部最終返回一個對象。  

  2.  優點:解決了創建多個相似對象的問題

  3.  缺點:不能確定對象的類型(即無法用 instanceof 去判斷)

二、構造函數模式

        function Car(color,type){
            this.color = color;
            this.type = type;
            this.sayColor = function(){ alert(this.color); };         }
        var car1 = new Car('red','CDV');
        var car2 = new Car('blue','SUV');
        car1.sayColor();  //red
        car2.sayColor();  //blue
        console.log(car1);
        console.log(car2);
        console.log(car1 instanceof Car);

  1、特點:

    • 沒有顯式創建對象
    • 屬性和方法賦給了this
    • 沒有 return 語句

  2、調用過程:

    • 使用new操作符創建一個新對象
    • 將構造函數的作用域賦給新對象(this就指向了新對象)
    • 執行構造函數里的代碼
    • 返回新對象

  3、優點:可將實例標識為一種特定類型(比如car1的類型就是Car,可用instanceof判斷)

  4、缺點:每個方法都要在每個實例上重新創建一遍。可以將其寫在外部共享,但又失去了封裝性。如下:

        function Car(color,type){
            this.color = color;
            this.type = type;
        }

        function sayColor(){ alert(this.color); }
        var car1 = new Car('red','CDV');
        var car2 = new Car('blue','SUV');
        sayColor.call(car1); //red,這里通過call來改變作用域 sayColor.call(car2); //blue,這里通過call來改變作用域         console.log(car1);
        console.log(car2);
        console.log(car1 instanceof Car);

  

三、原型模式

        function Car(){
        }
        Car.prototype.color = 'red';
        Car.prototype.type = 'SUV';
        Car.prototype.sayColor = function(){
            alert(this.color);
        }
        var car1 = new Car();
        var car2 = new Car();
        
        car1.sayColor(); //red 來自原型
        car2.sayColor(); //red 來自原型
        car1.color = 'blue'; //屏蔽了原型的color,但沒有覆蓋,原型的color還在
        alert(car1.color);  //blue 來自實例
        alert(car2.color);  //red  來自原型

  1、原型、構造函數與實例的關系:每個構造函數都有一個原型對象(prototype屬性),原型對象包含一個指向構造函數的指針(constructor),實例包含一個指向原型對象的指針(__proto__)。實例與構造函數沒有直接關系。

  2、訪問一個對象屬性的過程:在上面代碼中,比如car2.color ,先問car2實例上有color屬性嗎?沒有,則查找原型,car2原型上有color屬性嗎?有,則返回。再比如car1.color ,先問car1上有color屬性嗎?有,則返回。就不需要查找原型了。

  3、判斷屬性是否存在於實例中:hasOwnProperty() , true——實例

  4、優點:屬性和方法可以共享,並且可以在實例上重新定義屬性,而不改變原型。

  5、缺點:由於共享,對於引用類型,在實例上進行修改,也會改變原型的值。如下:

  

        function Person(){
        }
        Person.prototype = {
            constructor:Person,  //防止一些操作切斷構造函數與原型的關系
            name:'Jemma',
            friends:['Lucy','Jack']
        }
        var person1 = new Person();
        var person2 = new Person();
        console.log(person1.name); //Jemma
        console.log(person2.name); //Jemma
        //改變基本類型的屬性
        person1.name = 'King';
        console.log(person1.name); //King
        console.log(person2.name); //Jemma
        //改變引用類型
        person1.friends.push('Marry');
        console.log(person1.friends); //["Lucy", "Jack", "Marry"]
        console.log(person2.friends); //["Lucy", "Jack", "Marry"]

  

四、構造函數+原型模式(一般使用這個)

        function Person(name,age){
            this.name = name;
            this.age = age;
        }
        Person.prototype = {
            constructor:Person,  //防止一些操作切斷構造函數與原型的關系
            sayName:function(){
                alert(this.name);
            }
        }
        var person1 = new Person('Jemma',19);
        var person2 = new Person('King',21);
        console.log(person1.name); //Jemma
        console.log(person2.name); //King
        person1.sayName(); //Jemma
        person2.sayName(); //King

  特點:所有實例共享的屬性和方法原型中定義;自己獨有的在構造函數定義。

  優點:既可以共享,又有特定類型。


 

  其實關於這些細節可以講很多東西,我這里只是簡單總結一下。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM