• JavaScrip之对象与继承


      这章主要学习对象、原型、原型链和继承,比较核心,所以单独整理这一章的内容。

      理解对象:一组名值对,值可以是数据或函数。

    属性类型:1数据属性:包含一个数据值的位置。在这个位置可以读取和写入值,4个描述其行为的特性:

                [[Configurable]]表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性,默认true;

                [[Eenmuerable]]表示能否通过for-in循环返回属性,默认true;

                [[Writable]]表示能否修改属性的值,默认true;

                [[value]]:包含这个属性的值。读取属性的时候,从这个位置读,写入属性值的时候,把新值保存在这个位置,默认undefined.

            要修改属性默认的特性,必须使用ECMAScript的Object.defineProperty()方法 Object.defineProperty(Person(对象名),"name属性",{

             writable:false,value:...

            })

    2访问器属性:不包含数据值;包含一对getter和setter函数(不是必须),在读取访问器属性时,会调用getter函数,这个函数负责返回有效的值;在写入访问器属性的时候,会调用setter函数并传入新值,这个函数负责决定如何处理数据。

                [[Configurable]]表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为数据属性,默认true;

                [[Eenmuerable]]表示能否通过for-in循环返回属性,默认true;

                [[get]]在读取属性时调用的函数,默认undefined

                [[set]]在写入属性时调用的函数,默认undefined

             访问器属性不能直接定义,须使用ECMAScript的Object.defineProperty()方法

                var book={

                    _year:2004,

                    edition:1

                }  

                Object.property(book,"year",{

                    get:function(){return this.year},

                    set:function(newValue){if(newVlaue>2004){this._year=newValue;this.edition+=newValue-2004;}}

                })

                 book.year=2005;

                                alert(book.edition);

     6.2创建对象:

      1工厂模式:用函数来封装以特定接口创建对象的细节    

        function creatPerson(name,age,job){
          var o=new Object();
            o.name=name;
            o.age=age;
            o.job=job;
            o.sayName=function(){
            alert(this.name);
          };
          return o;
        }
      var person1=creatPerson('zhangfei',29,'killer');
      var person2=creatPerson('guanyu',30,'killer');

       2构造函数模式:创建自定义的构造函数,从而定义自定义对象类型的属性和方法

        function Person(name,age,job){
          this.name=name;
          this.age=age;
          this.job=job;
          this.sayName=function(){
            alert(this.name);
          };
        }
        var person1=new Person('zhangfei',29,'killer');
        var person2=new Person('guanyu',30,'killer');

        特点:没有显式的创建对象,直接将属性和方法赋给了this对象,没有return语句。 

        创建Person新实例:1创建一个新对象,2将构造函数的作用域赋值给新对象(this指向了这个对象);3执行构造函数中的代码(为新对象添加属性)4返回新对象

        存在问题:每个方法都要在每个实例上重新创建一遍(我的理解是每创建一个实例,实际上构造函数中的方法都是重新执行,创建了新的函数)

        解决方案:原型模式

        原型模式:重点中的重点.利用书中的图示,可以很好地理解,自己画一遍可以了。

        1 原型对象:只要创建新函数,就会为该函数创建一个prototype属性,这个属性指向函数的原型对象。所有原型对象都会自动获得一个constructor(构造函数)属性,这个属性指向prototype属性所在函数

       创建了自定义的构造函数之后,其原型对象默认只会取得constructor属性,当调用构造函数创建一个新实例后,该实例的内部包换一个指针[[Prototype]],指向构造函数的原型对象。(可以在Chrome浏览器中看到,即_proto_),这个连接存在于实例和构造函数的原型对象之间,而不存在于实例和构造函数之间。

      可以通过isPrototypeOf()方法来确定对象之间是否存在这种关系。                       Person.prototype.isPrototypeOf(person1)

       Object.getPrototypeOf(person1)方法可以返回[[prototype]]的值。

      当代码读取某个对象的属性时,会执行一次搜索,目标是具有给定名字的属性,搜索首先从对象实例本身开始,找到则返回,找不到则继续搜索指针指向的原型对象,如果在原型对象中找到,则返回

    (实例中添加一个属性,如果与实例原型对象中的属性同名,会屏蔽但不会修改原型对象中的值)

    使用hasOwnProperty()方法可以检测一个属性是存在于实例中还是存在于原型中,来自实例true,来自原型:false

        e: function Person() { }

          Peraon.protopyty = {

              constructor:Person, //这里使用字面量来简写,本质上重写了prototype对象,这里定义它指向Person构造函数

                name: '张飞',

                age: 29,

                job: 'killer',

            sayName: function () { }

        }

        var person1 = new Person();

        var person2 = new Person();

        person1.hasOwnPorpertype('name')//false

        person1.name = '李典';

        person1.hasOwnPorpertype('name')//true

        console.log(person1.name);//李典

        console.log(person2.name);//张飞

        delete person1.name;

        console.log(person1.name);//张飞

    原型与in操作符:单独使用in:对象能够访问属性就返回true  alert('name' in person1) //true

        问题:原型对象中的属性被所有实例共享,对于包含引用类型值的属性来说,就存在问题了,一个实例中属性变,导致都变。

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

      构造函数用于定义实例属性,原型模式用于定于方法和共享的属性e:

                  function  Person(name,skill,country) {

                    this.name=name;

                    this.skill=skill;

                    this.country=country;

                    this.member=["刘封","刘婵"];

                }

     

                Person.prototype={

                    constructor:Person,

                    sayUseSkill:function () {

                        alert(this.skill);

                    }

                }

                 var person1=new Person('马超','铁骑','蜀国');

                 var person2=new Person('刘备','仁德','蜀国');

                 person1.member.push('关羽');

                console.log(person1.member);

                console.log(person2.member);

                console.log(person1.member===person2.member);//false

                console.log(person1.sayUseSkill===person2.sayUseSkill);//true

    动态原型模式:在构造函数中初始化原型对象

        function  Person(name,skill,country) {

                    this.name=name;

                    this.skill=skill;

                    this.country=country;

                 if(typeof this.sayCountry !=undefined){

                     Person.prototype.sayCountry=function () {

                         alert(this.country);

                     };

                 }

                }

                var friend=new Person('张飞','咆哮','蜀国');

                friend.sayCountry();

    6.3 继承 涉及到原型链

      原型链:(继承:原型对象等于另一个类型的实例) 思想:利用原型让一个引用类型继承另一个引用类型的属性和方法

      首先先滤清构造函数、原型对象、实例之间的关系:每个构造函数有一个原型对象(构造函数有一个prototype属性指向原型对象),而原型对象有一个constructor属性指向构造函数,而实例中有一个内部属性(指针)[[Prototype]]指向原型对象

        如果然原型对象等于另一类型的实力,那么这个原型对象将包含指向另一个原型对象的指针,然后(另一个原型对象)又是第三个函数的实例,那么依然如上述,层层递进,就构成了原型链。虽然看着绕,但是动手画一画就很明晰了(我的理解是父函数的实例是子函数的原型)。

      例子:(添加了注释,这样看着图非常容易理解)  

        //父函数,他的实例中有[[Prototype]]属性和自定义的property属性

        function SuperType(){

        this.property=true;

        }

     

        //在SuperType原型对象中添加getSuperValue方法

        SuperType.prototype.getSuperValue=function(){

        return this.property 

          }

     

        //子函数,构造函数SubType,它的实例中有[[Prototype]]属性和自定义的subproperty属性

        function SubType(){

        this.subproperty=false;

          }

     

        //继承了SuperType (原型链)

        SubType.prototype=new SuperType();

     

        //在SubType原型对象中添加getSubValue方法

        SubType.prototype.getSubValue=function(){

    return tis.subproperty;

        };  

     

        var insatance=new SubType();

        alert(insatance.getSuperValue()); //true

     

     谨慎的定义方法:子类型有时候需要重写超类型中的某个方法,或者需要添加超类型中不存在的某个方法。给原型添加方法的代码一定要放在替换原型的语句之后。

      存在问题:还是引用类型值会改变,因为实例共享属性。

      经典继承(借用构造函数)

      在子类构造函数的内部调用超类构造函数

         相当于把父类的属性实例化到子类中?Java中的super() 存在疑问

        function SuperType(){

      this.colors=['red','blue','green'];

        }

        function SubType(){

        //继承了SuperTYpe

        SuperType.call(this);

         }

        var insatance1=new SubType();

        insatance1.colors.push('black');

        alert(insatance1.colors);// 'red,blue,green,black'

     

        var insatance2=new SubType();

        alert(insatance2.colors);//'red,blue,green'

        1传递参数:

          借用构造参数可以在子类型构造参数中向超类型构造参数传递参数

          function SuperType(name){

       this.name=name;

          }

          function SubType(){

        //继承了SuperTYpe,同时还传递了参数

        SuperType.call(this,'赵云');

     

        //实例属性

        this.age=29;

        }

        var insatance=new SubType();

     

        alert(insatance.name); //赵云

        alert(insatance.age); //29

    为了确保SuperType构造函数不会重写子类型的属性,可以在调用超类型构造函数之后,再添加应该在子类型中定义的属性。

    问题:方法都在构造函数中定义超类型中的方法对子类型不可见。

      组合继承

        原型链和构造函数技术组合到一起,使用原型链实现对原型属性和方法的继承,借用构造函数来实现对实例属性的继承。这样通过在原型上定义方法实现了函数的复用,有能够保证每个实例都有它自己的属性

        原型继承:方法可以,实例属性无法继承; 借用构造函数:实例属性可以,方法不行。 一起用,完美。

          function SuperType(name){

      this.name=name;

      thi.colors=['red','blue','green'];

        }

        SuperType.prototype.sayName=function(){

      alert(this.name);

        };

     

        function SubType(name,age){

      //继承属性

      SuperType.call(this,name);

      this.age=age;

        }

         //继承方法

       SubType.prototype=new SuperType();

     

       SubType.prototype.sayAge=function(){

        alert(this.age);

       }

     

      var instance1=new SubType('zhaoyun',29);

      instance1.colors.push('black');

      alert(instance1.colors); //'red,blue,green,black'

      instance1.sayName();//zhaoyun

      instance1.sayAge();//29

     

      var insatance2=new SubType('诸葛瑾',25);

      alert(instance2.colrs);'red,blue,green'

      instance22.sayName();//诸葛瑾

      instance2.sayAge();//25

     

    原型式继承

      object()方法  function object(o){

        function F(){};

        F.prototype=o;

        return new F();}

       对传入的对象执行了一次复制,在object()函数内部,先创建了一个临时性的构造函数,然后将传入的对象最为这个构造函数的原型,最后返回了这个临时了新的一个新实例。

      var person={

    name:'张飞',

    friends:['马超','刘备','赵云'];

    }

     

      var anothersPerson=object.create(person);

    anothersPerson.name='孙权';

    anothersPerson.friends.push('鲁肃');

     var yetAnothersPerson=object.create(person);

    yetAnohersPerson.name='曹操';

    yetAnothersPerson.friends.push('关羽');

     alert(person.friends);//马超,刘备,赵云,鲁肃,关羽

    寄生式继承

     

    使用hasOwnProperty()方法可以检测一个属性是存在于实例中还是存在于原型中,来自实例true,来自原型:false

    e: function Person() { }

    Peraon.protopyty = {

        name: '张飞',

        age: 29,

        job: 'killer',

        sayName: function () { }

    }

    var person1 = new Person();

    var person2 = new Person();

    person1.name = '李典';

    console.log(person1.name);

    console.log(person2.name);

    delete person1.name;

    console.log(person1.name);

     

    寄生组合式函数

      组合继承模式问题:会调用两次超类型构造函数,一次是在创建子类型原型的时候,另一次是在子类型构造函数内部,虽然子类型最终包含超类型对象的全部实例属性,但是在调用子类型构造函数时重写了这些属性。

       function SuperType(name){
        this.name=name;
        this.colors=['red','blue','green'];
      }
      SuperType,prototype.sayName=function(){
        alert(this.name);
      };
      function SubType(name,age){
      SuperType.call(this.name);//
    第二次调用SuperTyper()构造函数,相当于java中的super()?又在新对象上创建了实例属性name 和colors,因此屏蔽了原型中的两个同名属性。
      this.age=age;
      }
      SubType.prototype=new SuperType(); //
    第一次调用SuperType()构造函数,Subprototype会得到两个属性:name,colors,是父函数实例属性,位于子函数原型中
      SubType.prototype.constructor=SubType;
      SubType.prototype.sayAge=function(){
        alert(this.age);
      };

    解决方案:巧用原型式继承,传入对象由父类型对象变为父类型对象的原型。

     

  • 相关阅读:
    【转】从源码分析Handler的postDelayed为什么可以延时?
    android系统中如何通过程序打开某个AccessibilityService
    【转】在子线程中new Handler报错--Can't create handler inside thread that has not called Looper.prepare()
    【转】Android 增,删,改,查 通讯录中的联系人
    【转】Android调用Sqlite数据库时自动生成db-journal文件的原因
    【转】Android辅助功能AccessibilityService自动全选择文字粘贴模拟输入
    【转】Android中保持Service的存活
    Multi-label && Multi-label classification
    第2章 排序 || 第17节 三色排序练习题
    第2章 排序 || 第15节 有序数组合并练习题
  • 原文地址:https://www.cnblogs.com/hai233/p/5961457.html
Copyright © 2020-2023  润新知