1. 程式人生 > >javascript高階程式設計--建立物件的那些事兒

javascript高階程式設計--建立物件的那些事兒

瞭解完了物件,也瞭解了常用的建立物件的方式--建構函式式和字面量式,那麼除此自外,還有哪些建立物件的方式呢?

工廠模式

說白了就是一個封裝函式,在函式內部定義物件的細節,最後返回之

 function createObj(name,job,age){
             var obj = new Object();
             obj.name = name;
             obj.job = job;
             obj.age = age;
             obj.logAge = function(){
                 console.log(this.age)//該函式執行的時候是在物件中執行的所以,this指向物件本身
             }
             return obj
         }
            console.log(createObj("張三","小白",23))//是一個物件;
            var person = createObj("李四","會計",23);//person儲存了一個指標,指向新建立的物件;
            var person1 = person;//共同指向同一個物件
             console.log(person.logAge);//23
             console.log(person1);//還是一個物件

建構函式模式

a).由建構函式創建出來的是一個物件,
b).建構函式內部的this指向的是new 出來的例項物件;
c).例項.constructor是一個指標,指向例項的建立者--建構函式,預設呼叫的是prototype物件的constructors屬性;

d).建構函式歸根結底也是一個函式,只是呼叫方式不同,當然其作為函式,也是可以像普通函式那樣的呼叫的,只不過結果就不一樣啦;普通函式也是一樣,也可被當作建構函式那樣呼叫。
  function CreateObj(name, job, age){
           //  var hobby = "作詩";
            this.name = name;
            this.job = job;
            this.age = age ;
            this.logAge = function(){
                console.log(this.age)
            }
         }
         var person_new = new CreateObj("王五","財務",27);//person_new是一個物件;
         var person_new1 = new CreateObj("吳六", "飯店老闆", 46);//person_new是一個物件;
         person_new.logAge();//27
         person_new1.logAge()//46;
         console.log(person_new.constructor)//建構函式本身;
         console.log(person_new1 instanceof Object)//因為畢竟person_new1也是一個物件嘛!
         //建構函式當作普通函式呼叫;
         CreateObj("李白","詩人",48);//this此時指向的是window,因為呼叫的時候是在全域性環境中呼叫的;
         console.log(name)//李白

建構函式.prototype(原型模式):

每一個函式都有該屬性,是一個指標,指向一個物件(原型物件),該物件包含由該建構函式建立的所有例項物件所共有的屬性和方法;與此同時,該原型物件也包含著一個constructor屬性(是一個指標,指向擁有該原型物件的建構函式)

1.例項.__proto__:在通過建構函式建立例項後,該例項有一個屬性__proto__,是一個指標,指向該建構函式的原型物件。也就相當於,例項.__proto__ = 建構函式.prototype;

      function Plant(height,classify){
            this.height = height;
            this.class = classify;
         }
         Plant.prototype.name = "水稻";//將來所有的例項都將擁有屬性name,值為“水稻”
         console.warn(Plant.prototype.constructor)//建構函式本身;
         Plant.prototype.constructor.prototype.loca = "河南·許昌"//
         console.warn(Plant.prototype.constructor)//建構函式本身;

         var plant_xiaomai = new Plant(137,"旱季作物");//建構函式的例項
         console.log(plant_xiaomai);//一個物件
         console.log(plant_xiaomai.name)//水稻
         console.log(plant_xiaomai.loca);//河南.許昌
         console.log(plant_xiaomai.__proto__)//原型物件
2.訪問建構函式例項的屬性的搜尋順序:

當為例項物件新增一個屬性的時候,如果該屬性名和原型物件中的屬性名一樣,那麼該屬性就會遮蔽原型物件中的對應屬性,結果是會阻止我們 訪問原型中的對應屬性(但不會修改),因為在訪問例項中的某屬性的時候,首先會訪問例項中的屬性,如果有就停止搜尋,如果沒有就往建構函式的的原型物件中尋找
2.1例項.hasOwnProperty(prop):就是用來檢測屬性prop是存在於例項中還是對應建構函式的原型物件中,當存在於例項中時返回true,畢竟顧名思義--就是看看例項中有沒有屬性prop嘛,
2.2 原型模式也是有缺點的,其最大的缺點就是例項物件的屬性高度共享,因為prototype中的屬性是所有建構函式例項所共有的。 因此當修改原型物件中的屬性的時候,其它例項訪問該屬性的時候也會發生改變

//  訪問例項中的屬性的時候,其訪問機制是,首先會在例項中的屬性中尋找,如果找到了就停止尋找,如果找不到就在該例項的
           //建構函式的原型中尋找....
           function Xmw (name,sex,age){
               this.name = name;
               this.age = age;
               this.sex = sex;
           }
           Xmw.prototype.school = "陳楊寨楊村廟小學";
           var dmw = new Xmw ("董曼文","女",7);//一個物件
           console.log(dmw.school);//陳楊寨楊村廟小學
           console.log(dmw.__proto__);//指向建構函式的原型物件
           console.log(dmw.__proto__ == Xmw.prototype);//true
           var dhl = new Xmw("董涵琳","女",7);
           dhl.school = "吳劉小學"
           console.log(dhl.school)//吳劉小學;
           console.log(dhl.hasOwnProperty("school"));//true
           delete dhl.school;//刪除例項屬性
           console.log(dhl.school)//楊村廟小學,沒有了同名的例項屬性,就會尋找該例項的對應建構函式的原型中的屬性
建構函式和原型的正確開啟方式

1.建構函式+prototype混用(推薦):建立自定義型別的最常見方式,就是組合使用建構函式模式與原型模式。建構函式(可傳參)模式用於定義實
 例屬性,而原型模式用於定義方法和共享的屬性。

function Animal(name,age,weight){
             this.name = name;
             this.age = age;
             this.weight = weight;
             this.height = 1.03;
         }
         Animal.prototype = {
             constructor:Animal,//顯式指定constructor指標的指向
             sayAniName:function(){
                 console.log(this.name)
             }
         }
         var cat = new Animal("傲嬌Cat",1,5);//一個物件
         console.log(cat);
         cat.sayAniName()//傲嬌Cat
         cat.height =1.30
         console.log(cat.height)//1.30
         var dog = new Animal("憨厚Dog",2,20);//另一個物件
         console.log(dog.height)//1.03,因為dog例項物件中的height屬性是1.03
2. 動態原型模式(不推薦)
           function Animal_1(name, age, weight){
                this.name = name;
                this.age = age;
                this.weight = weight;
                this.height = 1.03;
                if(typeof this.sayAniName != "function"){//當例項中沒有sayAniName屬性的時候,
                                                        //這段程式碼只會在初次呼叫建構函式時才會執行。此後,原型已經完成初始化
                    Animal_1.prototype.sayAniName = function(){
                        console.log(this.name)
                    }
                }
           }
           var cat1 = new Animal_1("粘人貓",2,9);//新建立的例項,此時就會執行if語句,因為此時滿足跳撿,在此之後,當再次呼叫該建構函式的時候不執行if語句了
                                                //,因為此時例項已經有了公用的方法了
           cat1.sayAniName()//粘人貓
           var dog1 = new Animal_1("淘氣狗",2,10);
           dog1.sayAniName()//淘氣狗
3.寄生建構函式模式(不推薦):說白就是一個建構函式,在函式體內新建一個物件,然後定義物件的一些細節,最後返回物件 然後呼叫的時候使用 new 操作符
 function Plant(classify,iswatered){
                var plant = new Object();
                plant.classify = classify;
                plant.iswatered = iswatered;
                return plant
            }
            var apple = new Plant("灌木類",false);//既可以被當作建構函式使用
            var orange = Plant("草",true);//也可也被當作普通的函式使用
            console.log(apple);
            console.log(orange);
4.穩妥建構函式模式(一般用在安全性要求高的環境中)和寄生建構函式模式差不多,只不過在該模式下,新建立物件的例項方法不引用this(也就是說,在建構函式中定義物件例項細節的時不能使用this),其二不使用new操作符呼叫建構函式(要像呼叫普通函式那樣呼叫)
function Person(name, age, weight) {
                var person = new Object();
                person.alertName = function () {
                    alert(name)
                }
                return person
            }
            //新物件
            Person("張三", 23, 170).alertName();//張三

注意:

        函式物件有 __proto__ 屬性,又有 prototype 屬性。普通物件只有 __proto__ 屬性,沒有 prototype 屬性。

console.log(obj.__proto__)//Object物件
           console.log(obj.prototype)//undefined
           function abs(){
               console.log(1)
           }
           console.log(abs.__proto__)//function物件的原型
           console.log(abs.prototype)//將abs其視為一個物件,物件的原型是Object
  1. Function.prototype 比較特殊,是個空函式,因為Function是一個建構函式,建構函式.prototype指向該建構函式的原型物件

  2. typeof Function.prototype 輸出 “function” 但是它不能當成構造器,Function.prototype.prototype 為 undefined

  3. Object.prototype.__proto__ 為 null,原型鏈到這裡結束。