JS基础总结-对象继承(四)

  • 理解对象

  • 创建对象

  1. 工厂模式

    1. 创建示例
      function createCompany(name,age,job){
          var o = new Object();
          o.name = name;
          o.age = age;
          o.job = job;
          o.getName = function(){
              alert(this.name);
          }
          
          return o;
      }
      
      var company1 = createCompany('yiyi',25,'IT');
      var company2 = createCompany('xin',26,'doctor');

       

    2. 问题
      1. 可创建多个相似对象,但是却无法识别对象类型。
  2. 构造函数模式

    1. 创建示例
      function CreateCompany(name,age,job){
         
          this.name = name;
          this.age = age;
          this.job = job;
          this.getName = function(){
              alert(this.name);
          }
          
         
      }
      
      var company1 = new CreateCompany('yiyi',25,'IT');
      var company2 = new CreateCompany('xin',26,'doctor');

       

    2. 理解
      1. 调用构造器函数的过程
        1. 创建一个新对象
        2. 将构造函数的作用域赋给新对象(this就指向了这个新对象);
        3. 执行构造函数中的代码(为新对象添加属性);
        4. 返回新对象
      2. 通过构造器函数模式创建的对象,既是Object的实例,同时也是该构造器函数的实例。
        ​
        company1 instanceOf Object;//true
        company1 instanceOf CreateCompany;//true
        company2 instanceOf Object;//true
        company2 instanceOf CreateCompany;//true
        
        ​

         

    3. 注意
      1. 要创建构造函数的实例,必须使用new操作符。
      2. 使用构造函数,每个方法都要在每个实例上重新创建一遍。
      3. 不同实例上的同名函数是不相等的。
        alert(company1.getName == company2.getName); //false

         

      4. 要实现同名函数相同,我们可以把同名函数设置成全局函数,但是函数增多时,不利于实现封装。
        function CreateCompany(name,age,job){
           
            this.name = name;
            this.age = age;
            this.job = job;
            this.getName = getName;
            
           
        }
        //设置成全局函数
        function getName (){
           alert(this.name);
        }
        var company1 = new CreateCompany('yiyi',25,'IT');
        var company2 = new CreateCompany('xin',26,'doctor');

         

    4.  
  3. 原型模式

    1. 原型模式示例
      function Person(){};
      Person.prototype.name = 'yiyi';
      Person.prototype.age = 26;
      Person.prototype.sayName = function(){
          alert(this.name);
      };
      
      var person1 = new Person();
      var person2 = new Person();
      
      alert(person1.name);//yiyi
      alert(person2.name);//yiyi
      
      alert(person1.sayName == person2.sayName ); //true
      
      alert(Person.prototype.isPrototypeOf(person1));//true

       

    2. 使用原型对象的好处
      1. 让所有对象实例共享它所包含的属性和方法。
    3. 原型模式特点
      1. 可以通过对象实例访问原型对象中的值,但是却不能通过重写实例中的值去改变原型对象中的值。
        ​
        person1.name = 'qianxi';
        alert(person1.name);//qianxi  来自实例对象
        alert(person2.name);//yiyi    来自原型对象

         

      2. 对象实例中存在与原型对象同名属性,则会优先访问对象实例中的属性,断开与原型的连接,只有通过delete删除该属性时,才会重新与原型连接,访问原型中的该同名属性。

        person1.name = 'yixi';
        alert(person1.name);//yixi 来自对象实例
        
        person1.name = null;
        alert(person1.name);//null  来自对象实例
        
        alert(person1.hasOwnProperty('name'));//true
        
        delete person1.name;
        alert(person1.name);//yiyi 来自原型对象
        
        alert(person1.hasOwnProperty('name'));//false

         

      3. 引用类型值的属性,会在每个实例中实现共享,改变一个实例的该属性值则会更改所有实例的该属性值。

    4. 理解原型对象
      1. 只要创建一个函数,那么它就会拥有一个prototype属性,并且该属性指向该函数的原型对象。
      2. 每个原型对象都会有一个constructor(构造函数)属性,该属性包含一个指向prototype属性所在函数的指针。即函数原型对象的constructor属性指向该函数。Person.prototype.constructor = Person。
      3. 调用构造函数创建实例后,该实例会有一个指针【__proto__】,指向该构造函数的原型对象。
      4. 想要确定实例和构造函数的原型对象的关系,可以通过getPrototypeOf()来确定。Person.prototype.isPrototypeOf(person1);
      5. ECMAScript5新增一个方法:Object.getPrototypeOf()  获取对象的原型,这个方法对于利用原型实现继承非常重要。
      6. hasOwnProperty():判断属性是否属于对象实例。返回false说明属性来自原型。
      7. in操作符能确定该属性是否存在于对象实例或者原型中。配合hasOwnProperty()能确定属性是否存在于对象实例或者原型中。
        function hasPrototypeProperty(object, proName){
        
            return !hasOwnProperty(proName) && (proName in object);
        }

         

    5. 获取对象的属性
      1. for - in
        1. 示例
          function Person(){};
          Person.prototype.name = 'yiyi';
          Person.prototype.age = 26;
          Person.prototype.sayName = function(){
              console(this.name);
          };
          
          var person1 = new Person();
          var person2 = new Person();
          
          for(var prop in person1){
              console.log(prop,'====prop =');
          }
          // name ====prop =
          // age ====prop =
          // sayName ====prop =
          
          for(var props in Person.prototype){
              console.log(props,'=====Person type prop==');
          }
          // name =====Person type prop==
          // age =====Person type prop==
          // sayName =====Person type prop==
          
          person1.name = 'xin';
          person1.friends = 'jajka';
          for(var prop in person1){
              console.log(prop,'====prop change =');
          }
          //name ====prop change  =
          //friends ====prop change  =
          //age ====prop change  =
          //sayName ====prop change  =
          
          for(var prop in person2){
              console.log(prop,'====porp 2=');
          }
          //name ====porp 2=
          //age ====porp 2=
          //sayName ====porp 2=
          
          
          console.log(person1.name); //xin
          console.log(person2.name); //yiyi

           

        2. for - in既包含实例中的属性,也包括原型中的属性(但均为能通过对象访问的、可枚举属性)。
      2. Object.keys():接受一个对象作为参数,返回一个包含所有可枚举属性的字符串数组。均为对象自有可枚举的属性。
        1. 示例
          function Person(){};
          Person.prototype.name = 'yiyi';
          Person.prototype.age = 26;
          Person.prototype.sayName = function(){
              console(this.name);
          };
          
          var person1 = new Person();
          var person2 = new Person();
          
          var keys1 = Object.keys(Person.prototype);
          console.log(keys1); //['name','age','sayName']
          
          
          var keys2 = Object.keys(person1);
          console.log(keys2); //[]
          
          person1.name = 'xin';
          person1.friends = 'jajka';
          var keys3 = Object.keys(person1);
          console.log(keys3); //['name','friends']
          
          
          var keys4 = Object.keys(person2);
          console.log(keys4);//[]
          
          
          
          console.log(person1.name); //xin
          console.log(person2.name); //yiyi

           

        2. 注意
          1. 内置属性一般为不可枚举属性,当重新创建覆盖原来的属性时,该属性就变成了可枚举。
            //原型的属性对实例而言,默认是不可枚举的属性
            person1.name = 'xin';
            person1.friends = 'jajka';
            var keys3 = Object.keys(person1);
            console.log(keys3); //['name','friends']

             

      3. Object.getOwnPropertyNames():获取对象自有的所有属性,包括可枚举和不可枚举。
        1. 示例
          function Person(){};
          Person.prototype.name = 'yiyi';
          Person.prototype.age = 26;
          Person.prototype.sayName = function(){
              console(this.name);
          };
          
          var person1 = new Person();
          var person2 = new Person();
          
          //默认情况下,原生的constructor属性是不可枚举的
          var keys1 = Object.keys(Person.prototype);
          console.log(keys1); //["constructor", "name", "age", "sayName"]
          
          
          var keys2 = Object.getOwnPropertyNames(person1);
          console.log(keys2);//[]
          
          person1.name = 'xin';
          person1.friends = 'jajka';
          var keys3 = Object.getOwnPropertyNames(person1);
          console.log(keys3); //['name','friends']
          
          
          var keys4 = Object.getOwnPropertyNames(person2);
          console.log(keys4);//[]
          
          //定义一个不可枚举对象
          Object.defineProperty(person1, "age", {value:"18", enumerable:false});
          var keys5 = Object.getOwnPropertyNames(person1);
          console.log(keys5); //['name','friends','age']

           

      4.  
  4. 组合使用构造函数模式和原型模式

    1. 创建示例
      function Person(name,age,job){
          this.name = name;
          this.age = age;
          this.job = job;
          this.colors = ['red','green','blue']; 
      }
      
      Person.prototype = {
          constructor: Person,
          getName: function(){
              alert(this.name);
          }
      }
      
      var person1 = new Person('yiyi',25,'IT');
      var person2 = new Person('xin',26,'doctor');
      
      person1.colors.push('pink');
      alert(person1.colors);//['red','green','blue','pink'];
      alert(person2.colors);//['red','green','blue']
      alert(person1.colors == person2.colors); //false
      alert(person1.getName == person2.getName); //true

       

    2. 理解
      1. 实例属性是在构造函数中定义的,儿所有实例共享的属性constructor和方法则是在原型中定义的。
  5.  
  • 继承

  1. 原型链继承

    1. 示例
      function Parent(){
          this.name= 'yiyi';
      	this.age = 12;
      }
      
      Parent.prototype.getParentName = function(){
          return this.name;
      }
      
      function Child(){
          this.firstName = 'yixi';
      }
      
      //继承了Parent
      Child.prototype = new Parent();
      
      Child.prototype.getChildName = function(){
          return this.firstName;
      }
      
      var child1 = new Child();
      console.log(child1.getParentName()); //yiyi
      console.log(child1.getChildName ()); //yixi
      console.log(child1);

      child1的打印结果如下:

    2. 注意
      1. 通过原型链进行继承的时候,不能通过对象字面量去创建原型的方法,这样会重写原型链,断开原有原型链的连接。
        function Parent(){
            this.name= 'yiyi;
        }
        
        Parent.prototype.getParentName = function(){
            return this.name;
        }
        
        function Child(){
            this.firstName = 'yixi';
        }
        
        //继承了Parent
        Child.protoype = new Parent();
        
        //使用字面量增加新方法,会导致上面的代码失效
        Child.prototype = {
            getChildName: function(){
                return this.firstName;
            },
            getOtherName: function(){
                return 'other';
            }
        }
        
        var child1 = new Child();
        alert(child1.getParentName()); //报错

         

    3. 原型链的问题
      1. 引用类型值的原型属性,会被所有的实例共享。(改变一个引用类型值的原型属性的值,会更改所有实例)
      2. 创建子类型的实例时,不能想超类型的构造函数传参。
  2. 构造函数继承

    1. 使用示例
      function Parent(name){
          this.name= name;
          this.colors = ['blue','green','red'];
      	this.getName = function(){
      		console.log(this.name);
          }
      }
      
      Parent.prototype.getColors = function(){
      	console.log(this.colors);
      }
      
      function Child(){
          //继承了Parent
          Parent.call(this,'yiyi');
          this.age = 25;
      }
      
      
      
      var person1 = new Child();
      person1.colors.push('pink');
      console.log(person1.name); //yiyi
      console.log(person1.age); //25
      console.log(person1.colors);//['blue','green','red','pink']
      
      var person2 = new Child();
      console.log(person2.colors);//['blue','green','red']
      
      console.log(person1);  //Child {name: "yiyi", colors: Array(4), getName: ƒ(), age: 25}
      

       

    2. 问题
      1. 方法都在构造函数中定义,不符合函数复用。
      2. 超类型的原型中定义的方法,对子类型而言是不可见的。如上查看实例,没有超类型原型中定义的getColors方法。
  3. 组合继承

    1. 思路:使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。
    2. 使用示例
      function Parent(name){
          this.name= name;
          this.colors = ['blue','green','red'];
      }
      
      Parent.prototype.getName = function(){
          alert(this.name);
      }
      
      function Child(name,age){
          //继承了属性
          Parent.call(this,name);
          this.age = age;
      }
      
      //继承方法
      Child.prototype = new Parent();
      Child.prototype.getAge = function(){
          alert(this.age);
      }
      
      
      var person1 = new Child('yiyi',25);
      person1.colors.push('pink');
      alert(person1.getName()); //yiyi
      alert(person1.getAge()); //25
      alert(person1.colors);//['blue','green','red','pink']
      
      var person2 = new Child('xinxin',18);
      alert(person2.getName()); //xinxin
      alert(person2.getAge()); //18
      alert(person2.colors);//['blue','green','red']
      

       

  4. 原型式继承

    1. 创建示例
      function object(o){
          function F(){};
          F.prototype = o;
          return new F();
      }
      
      var person = {name: 'yiyi',colors:['green','red','blue']};
      
      var person1 = object(person);
      person1.name = 'yixi1'; //yixi1
      person1.colors.push('pink');
      
      var person2 = object(person);
      person2.name = 'yixi2'; //yixi2
      person2.colors.push('yellow');
      
      console.log(person1.colors);//['green','red','blue','pink','yellow'];
      console.log(person2.colors);//['green','red','blue','pink','yellow'];
      console.log(person.colors); //['green','red','blue','pink','yellow'];

       

    2. 原型式继承解析
      1. 在object()函数内部,先创建了一个临时性的构造函数,然后将传入的对象作为这个构造函数的原型,最后返回了这个临时类型的一个新实例。
      2. object()对传入其中的对象执行了一次浅复制
    3. Object.create()
      1. ECMAScript5新增了Object.create()方法规范化了原型式继承。Object.create()与object()行为相同。
    4. 适用场景
      1. 只想让一个对象与另一个对象保持一致。
    5. 注意
      1. 包含引用类型值的属性始终都会共享相应的值,就像使用原型模式一样
    6.  
  5.  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值