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,原型链到这里结束。

更多信息请参考:JavaScirpt深入之从原型到原型链


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值