• javascript面向对象(二)--创建对象


      1 /创建对象:
      2     //最基本的   Object构造以及字面量法
      3     //一、工程模式创建:使用参数传值在构造
      4     function createObject(name,age,job){
      5         var o = new Object();
      6         o.name = name;
      7         o.age = age;
      8         o.job = job;
      9         o.sayName = function(){
     10             alert(this.name);
     11         };
     12         return o;
     13     }
     14     var person = createObject('zhd',23,'Software Engineer');
     15     //该方式无法确定  该对象是一个什么样的类型(都是有Object创建的)
     16 
     17     //二、构造函数模式:改进工厂模式
     18     function Person(name,age,job){  //约定俗成 首字母大写
     19         var o = new Object();
     20         this.name = name;
     21         this.age = age;
     22         this.job = job;
     23         this.sayName = function(){
     24             alert(this.name);
     25         };
     26         //也可以像下面这种方式定义,这种方式定义会导致不同的作用域链和标识符解析,例:
     27         //alert(person1.sayName == person2.sayName) //false
     28         //但创建机制还是一样的
     29         //this.sayName = new Function("alert(this.name");  //没有大括号 
     30     }
     31     var person = new Person('zhd',23,'Software Engineer');  //构造方法
     32     //每个对象都有一个 constructor指向构造函数,因此   
     33     alert(person.constructor == Person); // true
     34     alert(person instanceof Person);    //true
     35     alert(person instanceof Object);    //true  所有的对象均继承自Object类
     36 
     37     //构造函数也是函数,所有用new出来的函数,都可以做构造函数来看待
     38     var person = new Person('zhd',23,'Software Engineer');
     39     person.sayName(); // zhd
     40     
     41     Person('qi',23,'Software Engineer'); //普通函数来看待
     42     window.sayName(); // qi 只能是Global(浏览器时window)调用
     43 
     44     var o = new Object();
     45     Person.call(o,'qi',23,'Software Engineer'); //普通函数来看待
     46     o.sayName(); // qi 在 对象o中调用
     47 
     48     //可以把sayName()对象转移到函数体外部,this指针的存在,可以保证在构造函数调用外面的sayName()时,
     49     //两个对象不会产生混乱
     50     function Person(name,age){
     51         this.name = name;
     52         this.age = age;
     53         this.sayName = sayName;
     54     }
     55     function sayName(){alert(this.name);}
     56 
     57     //三、原型方法 
     58     //对于构造函数模式来讲,可以把对象中若干个函数移出构造函数体外部,成为全局变量。
     59     //然而,这些函数并不是真正意义上的全局变量,大多数情况下仍然是声明出来的某个对象所调用
     60     //况且,方法过多让大量的方法在作为全局变量游离在构造方法之外,破坏了封装型
     61     //可以使用原型模式来解决
     62 
     63     //创建的每个函数都有一个 prototype属性,这是一个指针,指向一个对象,这个对象的用途就是
     64     //包含可以由特定类型的所有实例共享的属性和方法
     65     //通过调用构造函数而创建那个对象实例的原型对象
     66     //好处就是让所有对象实例共享它所包含的属性和方法
     67     //也就是说 不必在构造函数里定义对象的信息,可以将信息直接添加到原型对象中去
     68     function Person(){};
     69     Person.prototype.name = "zhd";
     70     Person.prototype.age = 23;
     71     Person.prototype.sayName = function(){
     72         alert(this.name);
     73     };
     74 
     75     var person1 = new Person();
     76     person1.sayName(); //zhd
     77     var person2 = new Person();
     78     person1.sayName(); //zhd    //所有实例共享属性和方法,与构造函数模式不同
     79 
     80     alert(person1.sayName == person2.sayName); //true 没有(),这里比较的是两个指针
     81 
     82     //理解原型对象  (这个对象可以理解为实实在在存在的一个对象,并且与这个函数息息相关)
     83     //只有创建一个函数,就会根据一组特定的规则为这个函数创建一个prototype属性指向函数的原型对象。
     84     //默认情况下,所有的原型对象都会自动获得一个constructor属性,这个属性包含一个指向prototype属性
     85     //所在函数的指针。例如:Person.prototype.constructor指向Person。
     86     //创建自定义构造函数后,其原型对象默认只会获取constructor属性。至于其他方法都是Object继承而来
     87     //每创建一个新实例,该实例都会包含一个指针指向构造函数的原型对象。
     88     //ECMA-262第五版称之为  [[prototype]]
     89 
     90     //它们之间的关系就是:
     91     //每个新实例会有一个指针指向构造函数的原型对象。
     92     //给构造函数的原型对象赋值。
     93     //也就是说每个新实例都会得到原型对象中属性的值。
     94     //因此 alert(person1.sayName == person2.sayName)返回true
     95     //所有的实例共享构造函数的原型对象中的属性和方法
     96 
     97     //可以通过 isPrototypeOf() 方法来确定是否有这么一层关系
     98     alert(person.prototype.isPrototypeOf(person1)); //true
     99 
    100     //ECMAScript 5中的 Object.getPrototypeOf() 可以很方便的获取一个实例的原型对象
    101     alert(Object.getPrototypeOf(person1) == Person.prototype); //true
    102     alert(Object.getPrototypeOf(person1).name); //zhd
    103 
    104     //程序在读取实例属性的时候,会先后搜索两次属性的名称  以 name为例
    105     //第一次在实例person1中查找name
    106     //如果未找到,就会在person1的原型对象中查找name
    107     //因此可以直接在实例中,定义一个与源性对象中属性相同的名字,程序就会屏蔽原型对象中的值
    108     //只是在这个实例中屏蔽,不会改变原型对象的值
    109     var person3 = new Person();
    110     person3.name = 'zhdqi';
    111     alert(person3.name);    //zhdqi
    112     alert(person1.name);    //zhd   不会改变
    113 
    114     //delete person3.name;
    115     //alert(person3.name);    //zhd  删掉实例同名的属性后,就会继续访问原型对象中的值
    116 
    117     //可以使用 hasOwnProperty(); 判断访问的对象属性来自实例还是来自原型对象
    118     alert(person1.hasOwnProperty("name")); //false 来自原型
    119     alert(person3.hasOwnProperty("name")); //true 来自实例对象  
    120 
    121     //in操作符:可以确定在实例中能否访问某个属性,无论属性是实例还是原型对象
    122     alert("name" in person1); //true name来自原型对象 只要能访问到 就是true
    123     alert("name" in person3); //true  name来自实例本身
    124 
    125     //同时使用hasOwnProperty和in能够确定访问的属性的值来自与原型对象还是实例本身
    126     function hasPrototypeProperty(object,name){
    127         return !hasOwnProperty(name)&&(name in object);
    128     } 
    129     alert(hasPrototypeProperty(person1,'name')); //true 能访问 且来自原型对象
    130     alert(hasPrototypeProperty(person3,'name')); //true 能访问 来自实例本身
    131 
    132     //for-in能够访问对象中可枚举的属性(不论属性来自实例还是原型对象)
    133     //如果原型对象某属性屏蔽了可枚举性,但实例中重新定义了该属性,那么for-in也是可以访问的
    134     //使用 Object.keys(),会返回一个对象中所有可枚举实例属性的字符串数组 注意:是实例属性
    135     alert(Object.keys(person.prototype)); //'name','age','job'
    136     alert(Object.keys(person3)); //'name' 实例对象的属性
    137 
    138     //Object.getOwnPropertyNames(Person.pertotype) 返回所有实例的属性
    139     alert(Object.getOwnPropertyNames(Person.pertotype)); //constructor,name,age,job,sayName
    140 
    141     //更简单的语法
    142     function Person(){}
    143     Person.prototype = {
    144         name:'zhd',
    145         age:23,
    146         job:'Software Engineer',
    147         sayName:function(){alert(this.name);}
    148     }
    149 
    150     //!!!这样相当于重写了 prototype对象,因此 constructor指向新的constructor对象(Object)    
    151     //原型对象是一个已经存在的对象,因此可以在上面随意的增加删除属性与方法
    152     //但是使用字面量法重新定义之后,就相当于重写该方法
    153     //使用instanceof操作符还会有正确的结果,但是constructor无法确定对象的类型了
    154     var friend = new Person();
    155     alert(friend instanceof Object); // true
    156     alert(friend instanceof Person); // true
    157     alert(friend.constuctor == Person); // false
    158     alert(friend.constuctor == Object); // true
    159     //假如constuctor值很重要
    160     Person.prototype = {
    161         //constuctor:Person,      //可以直接指定  但这样会变成可枚举类型,而默认是不可枚举的
    162         name:'zhd',
    163         age:23,
    164         job:'Software Engineer',
    165         sayName:function(){alert(this.name);}
    166     }
    167     Object.defineProperty(person.prototype,"constructor",{
    168         enumerable:false,   //重设constructor,使其变成不可枚举的值
    169         value:Person 
    170     });
    171 
    172     //实例与构造函数之间是一种松散关系,可以在原型对象上任意定义与删除方法都可以反映在实例上
    173     //pertotype作为实例与构造函数之间的桥梁
    174     //一旦重写了pertotype,就相当于切断了这层关系
    175     function Person(){}
    176     var friend = new Person();
    177     Person.prototype = {        //重写了方法  桥梁被切断
    178         constuctor:Person,
    179         name:'zhd',
    180         age:23,
    181         job:'Software Engineer',
    182         sayName:function(){alert(this.name);}
    183     }
    184     alert(friend.sayName); // undefined 他引用的依旧是最原始的原型对象
    185 
    186     //原生对象的原型:即 Object,Array,String等原生引用类型的方法也是可以在其原型对象上找到
    187     //例如 可以在 Array.prototype找到sort()方法,也可以在String.prototype中找到substring方法
    188 
    189     //通过原生对象的原型,可以在原生类型上随时添加新的方法
    190     //例  在String添加一个 startsWith()
    191     String.prototype.startsWith = function(text){
    192         return this.indexOf(text) == 0;
    193     }   
    194     var msg = "hello world";
    195     alert(msg.startsWith('hello')); //true
    196 
    197     //原型对象的局限性
    198     //这种创建对象的方式是基于共享的,在原型对象中,每一个实例都可以重新定义(修改)原型中已有的属性
    199     //且不会共享。但是,如果原型中带有引用类型的变量,例如,原型中有一个数组,那么在对数组进行操作而没有
    200     //重新定义的时候,那么这个被操作的数组就会被所有实例所共享
    201     function Person(){}
    202     Person.prototype = {        //重写了方法  桥梁被切断
    203         constuctor:Person,
    204         name:'zhd',
    205         age:23,
    206         likecolor:['red','green'],
    207         job:'Software Engineer',
    208         sayName:function(){alert(this.name);}
    209     }
    210     var person1 = new Person();
    211     var person2 = new Person();
    212     person1.likecolor.push('blue');   //这里会共享
    213     alert(person1.likecolor);   //red green blue
    214     alert(person2.likecolor);   //red green blue
    215     alert(person1.likecolor == person2.likecolor); //true
    216 
    217     //四、结合构造函数模式以及原型对象模式创建对象  最流行的一种方法
    218     //构造函数模式用于 定义实例属性
    219     //原型对象模式    定义实例方法以及共享的属性
    220     //每个实例都有自己的一份属性的副本,且共享着对方法的引用
    221     function Person(name,age,job){
    222         this.name = name,
    223         this.age = age,
    224         this.job = 'Software Engineer'
    225     }
    226     Person.pertotype = {
    227         constuctor:Person,
    228         sayName:function(){
    229             alert(this.name);
    230         }
    231     }
    232     //五、动态原型模式
    233     //所谓动态原型,就是追求一种封装的效果。将原型对象的方法放到了构造函数中,通过if判断的方式动态的加载原型对象的方法
    234     //判断只需要判断其中一个方法(如果有若干个方法的话),作用就是判断构造函数是否已经加载了原型对象中的方法
    235     //与原型模式一样,使用字面量法重写原型会切断实例与构造函数之间的桥梁
    236     function Person(name,age,job){
    237         this.name = name;
    238         this.age = age;
    239         this.job = job;
    240 
    241         //if(Person.pertotype.method == undefined)  /这样写也可以
    242         if(typeof this.sayName != "function"){
    243             //加载原型对象的函数到构造函数
    244             Person.pertotype.sayName = function(){
    245                 alert(this.name);
    246             };
    247         }
    248     }
    249     //六、寄生构造函数模式  与工厂模式基本相同
    250     function Person(name,age){    //函数名称不再是  createObject
    251         var o = new object();
    252         o.name = name;
    253         o.age = age;
    254         o.sayName = function(){
    255             alert(this.name);
    256         };
    257         return o;
    258     }
    259     var person1 = new Person('zhd',23);
    260     person1.sayName(); // zhd
    261 
    262     //在特殊场合下使用这种方式,但无法通过 instanceof 确定对象的类型,与工厂模式类似
    263     //比如创造一个具有一个额外方法的特殊数组,由于不能修改Array函数,那么可以这么做:
    264     function SpecialArray(){
    265         var array = new Array();  //先创建一个数组
    266         array.push.apply(array,arguments);  //调用apply方法接受SpecialArray的参数给array的push赋值,进而给数组赋值
    267         array.toPipeString = function(){
    268             return this.join("|");
    269         };
    270         return array;   //返回数组
    271     }
    272     var colors = new SpecialArray("red","green","blue");  // red,green,blue
    273     colors.toPipeString(); //red|green|blue
    274 
    275     //七、稳妥构造函数模式 :与寄生构造模式类型,但 1.新创建的实例方法不引用this 2.不能使用new调用构造函数
    276     //使用于较为安全的环境(禁止使用this于new)
    277     //由于没有this和new,构造函数中的数据成员无法被外部访问,只能被函数体内定义好的方法来访问
    278     //在外部添加方法时,不能使用this指针,也无法在方法体内引用函数的数据成员变量
    279     function Person(name,age){
    280         var o = new Object();
    281         //定义若干方法
    282         o.name = name;
    283         o.age = age;
    284 
    285         o.sayName = function () {
    286           alert(name);  
    287         };
    288         return o;
    289     }
    290     var friend = Person('zhd',23);
    291     friend.sayName(); //zhd
    292     //alert(friend.name);  //浏览器会忽略这条语句 
  • 相关阅读:
    heml学习笔记
    离线安装
    linux 监测网络流量的工具 ifstat
    Python的 “内存管理机制”,转载,内存泄漏时感觉应该看下
    http 请求
    Java之调用Python代码 转载:https://mp.weixin.qq.com/s/cr8dXzwsQhtei9TfXwcMcA
    python 加密 so 转载:https://mp.weixin.qq.com/s/xmr3fs72XeJn-sMIoGftNA
    migrate
    查看 GPU 基本信息 nvidia-smi 命令
    MVC 基于 AuthorizeAttribute 实现的登陆权限控制
  • 原文地址:https://www.cnblogs.com/luckyQi/p/7518588.html
Copyright © 2020-2023  润新知