07 JSCORE 面向对象OOP

回顾:
1. *****闭包:
   笔试: 快速绘制闭包图
       1. 受保护的变量,并确定外层函数调用后,变量的值
       2. 找所有操作受保护变量的内层函数

正课:
1. *****面向对象OOP:(封装、*****继承、多态)
   什么是: 用对象来描述现实中一个具体事务,程序中都是先用对象来定义数据和功能,再按照逻辑的需要,访问对象中的数据和功能。
   为什么: 和现实中人的想法非常接近。便于大程序的维护。
   什么是对象: 内存中同时存储多个数据和功能的存储空间
              描述现实中一个具体事物的属性和功能的程序结构
                     事物的属性,会成为对象中的属性
                     事物的功能,会成为对象中的方法

                    事物的属性和方法称为对象的成员
   何时: 今后开始写程序前,都要先用对象,描述好要操作的事物的属性和功能,再按需使用对象的功能,访问对象的属性
   如何: 面向对象三大特点(即支持的3个功能): 封装,继承,多态
      封装: 将一个具体事物的属性和功能集中定义在一个对象中
      创建自定义对象: ——封装   3种:
         1. 使用对象直接量:
              var obj={
                  属性名: 属性值,
                         ... : ... ,
                  方法名: function(){... this.属性名 ...},
                         ... : ... ,
              }

        何时:创建时就已经知道对象的所有成员

          调用:obj.属性  obj.方法 

*****什么是this:引用正在调用函数的对象的关键词,简单说,就是点前的对象

        为什么:方法中不加this的变量,默认仅在作用域链中进行查找,不会去对象中查找

        何时:只要对象的方法想使用对象自己的属性时,必须加this
          强调: 对象自己的方法,要访问自己的属性,必须用this.属性名.

                

     

     

       2. 使用new: 2步:  
          var obj=new Object(); //创建一个空对象
          //向空对象中添加属性和方法
          obj.属性名=属性值;
          obj.方法名=function(){...this.属性名...};
          
     ***js中一切对象的底层都是关联数组
          每个属性/方法都是关联数组中的元素      obj.属性==》obj["属性"]
          属性名/方法名是key,属性值/函数对象是value

      ***通用的简写(不仅仅是Object,还有Date等等,省略括号时要注意括号里面没有参数):

                                                                                                         var lilei=new Object  或者  var lilei=Object()

      

      问题: 一次只能创建一个对象
       3. 解决: 用构造函数:(程序中,只要有重复的代码,就是不对的,就是有隐患的)
          什么是构造函数: 专门描述一类对象统一结构的函数
          何时: 今后只要反复创建多个相同结构的对象时,都要先定义构造函数
          为什么: 复用对象的结构代码
          如何: 2步:
            1. 定义构造函数
                function 类型名(属性参数列表){
                     this.属性名=属性参数值;
                               ...=...;
                     this.方法名=function(){ ... this.属性名 ...  }
                }
            2. 用new调用构造函数,创建并装修新对象
                var obj=new 类型名(属性值列表);
                     创建一个指定“类型”的对象
                     用new调用指定"类型"的构造函数来创建对象
              new: 4件事:
                1. 创建新的空对象
                2. 让新对象继承构造函数的原型对象
                3. 用新对象继承构造函数的原型对象:

                     设置新对象的--prototype--
                      向新对象中添加构造函数规定的属性
                      将属性参数的值,保存到新对象的新属性中
                      向新对象中添加构造函数规定的方法
                4. 将新对象的地址保存在变量

     优点:代码重用

     缺点:内存浪费

     解决:继承

      按需访问对象的属性,调用对象的方法:  
         访问对象的属性: obj.属性名   用法和普通的变量完全一样
                属性就是保存在对象中的一个变量
         调用对象的方法: obj.方法名() 用法和普通的函数完全一样
            强调: 方法中的this,默认指.前的对象

      构造函数的问题: 只能复用代码,不能节约内存

*****继承: 父对象的成员,子对象不用重复创建,也可直接使用
      为什么: 即节约内存,又代码重用
      何时: 只要一类子对象,需要相同的属性和功能时,都要将相同的属性和功能仅在父对象中定义一次即可供所有子对象使用
      如何:买一赠一:每创建一个构造函数,都会自动赠送一个原型对象,用new创建子对象时,会自动设置子对象的--proto--继承构造函数的prototype.

      如何向原型对象中添加共有成员:
           构造函数.prototype.属性=值;

           构造函数.prototype.方法=function(){...}

   原对象: 集中存储同一类型的子对象所需的所有共有属性和方法的父对象

  
       

正课:
1. *****OOP
   内置对象的原型对象
   共有属性和自有属性
   原型链
   原型相关API
*****自定义继承

2. 共有属性和自有属性:
   自有属性: 直接保存在对象本地的属性
   共有属性: 保存在父级原型对象中的属性
   访问共有/自有属性:
      读取属性值: 即可用子对象读取,也可用原型对象读取
      修改属性值:
          自有属性: 子对象.属性名=值
          共有属性: 构造函数.prototype.属性名=值
   如何判断自有还是共有:
      自有: var bool=obj.hasOwnProperty("属性名")
          判断obj中是否包含自有属性"属性名"
      共有: 不是自有! 且 属性名 in 对象名           子对象可访问到!

  

1. 内置对象的原型对象:
   所有内置对象都是一个构造函数(除Math外)
   每类内置对象都有自己的原型对象(prototype)
   所有内置对象的API都保存在类型.prototype对象中
   何时: 解决浏览器兼容问题: 2步:
      如果类型.prototype.方法===undefined
         类型.prototype.方法=function(...){
            this->自动获得将来调用该方法的当前对象
         }

    内置对象的继承关系:
          1、凡是可以new的类型,都是构造函数

          2、每个内置对象的构造函数都对应一个内置的原型对象

          3、内置类型的原型对象中保存着该类型所有子对象共用的API

          可解决浏览器兼容性问题,一个API新的浏览器支持,旧的不支持!

         解决:if(typeof 内置对象.prototype.API!="function")

                          内置对象.prototype.API=function(){

                          ........this//将来调用API的.前的对象

}

   

   

3. ***原型链(prototype chain):
   什么是原型链: 多级父对象逐级继承,形成的链式结构
      保存了: 对象的属性和方法
      控制了: 对象的成员的使用顺序
         优先使用自有成员
         自己没有才延原型链向父级查找,只要找到就不再向上
         如果整个原型链上都没有,才返回undefind

         原型链的顶端一定是object.prototype
   vs 作用域链(scope chain)
      保存了: 全局/局部的变量
      控制了: 变量的使用顺序
         优先在当前函数调用的函数作用域对象(AO)中查找
         如果函数作用域对象(AO)中没有,才延作用域链向全局方向查找。只要找到,就不再继续
         如果整个作用域链上都没有,才报错

        作用域的终点:window

简单概括:

         所有不需要“对象”.访问的变量都保存在作用域链中

         所有必须用“对象”.访问的变量都保存在原型链中

鄙视题: 判断一个对象是不是数组类型,有几种方式
   0. typeof只能区分基础类型和function
              无法进一步区分对象的类型
   1. 判断原型对象:
     如果obj的原型是Array.prototype说明是数组
      obj.__proto__==Array.prototype
      问题: __proto__是内部属性,本来浏览器是禁止使用的
      解决: Object.getPrototypeOf(obj)
               获得obj的原型对象
      

正课:
1. *****OOP
   原型链
*****自定义继承

1. 原型链:
  判断一个对象是不是数组类型,有几种方法: 4种
  0. typeof 只能识别原始类型,function和object,无法进一步识别object中的不同对象类型
  1. 判断原型对象:
     obj.__proto__==Array.prototype
         问题: __proto__是内部属性,可能不允许使用
         Object.getPrototypeOf(obj)==Array.prototype
              问题: 只能判断直接父对象是Array.prototype的情况
                       无法判断间接继承Array.prototype的情况
              解决: var bool=father.isPrototypeOf(child)
                  判断father是否是child的父级对象
                     不但检查直接父对象,且检查整个原型链!
   2. 判断构造函数:
       每个原型对象都有一个constructor属性指回构造函数
       obj.constructor==Array
       还可以用: obj instanceof Array
          instance: 实例-用一个构造函数创建出的一个具体对象
         比如: var lilei=new Student(...);
                 称lilei是Student类型的一个实例
                 实例化一个Student类型的对象lilei
          检查整个原型链

   要求不够严格: 即使创建时不是使用数组创建的,但是只要原型链上有数组类型,只要有继承关系,就认为是数组
   要求严格: 只有用数组类型创建的对象,才是真正的数组。

   3. 检查对象的内部属性class
      什么是class: 对象的内部属性,专门保存创建对象时使用的类型名。(类似每个对象的DNA)

      class一旦创建,无法被修改
       只有一个办法获得class属性值:
          调用Object.prototype.toString();->"[object Class]"
      问题: 所有内置对象都重写了Object中的toString
         重写(override): 如果子对象觉得,父对象的成员不好用,可在本地定义同名的自有成员,覆盖父对象中的。
                                                                                                          ——多态(同一事物,在不同情况下表现出不同的状态)

         为什么:体现子对象与父对象之间的差异

         何时:只要子对象觉得父对象的方法不好用
      解决: 用call强行借用
        call: 强行借用一个本无法调用的方法
        何时:  想调用一个原本无法调用的方法
        如何: 想借用的函数.call(要替换的对象)
             比如: Object.prototype.toString.call(obj)
                         相当于: obj.toString()
                         返回: "[object Class]"

   4. Array.isArray(obj);
      问题: ES5   IE9+
      解决: 自定义isArray方法

鄙视题: 对象实例方法 vs 构造函数方法
     对象实例方法: 必须用一个对象实例才能调用的方法
                            仅当前类型的对象可用!
        对象实例方法一律保存在该类型的原型对象中,所有子对象共用。
        何时: 一个方法只希望当前类型的子对象才能使用时
     构造函数方法: 不需要任何对象实例,用构造函数即可直接调用的方法。
       构造函数方法一律保存在构造函数对象上
        何时: 一个方法的执行和对象的类型无关时

2. *****自定义继承关系:
    1. 仅设置两个对象间的继承关系:
       child.__proto__=father;
       问题: --proto--也是内部属性,有可能被浏览器禁用

        解决:内部属性API: Object.setPrototypeOf(child,father);
                   设置child继承father

      
        

    2. 批量修改多个对象的继承关系:
       直接修改构造函数的prototype引用新的父对象
       obj.prototype=father

       时机:定义完构造函数就写
       强调: 必须在创建第一个子对象之前就换
    3. 两种类型间的继承: 最像Java的继承
      何时: 只要两种类型间包含相同的属性结构定义或相同的方法。
      如何: 3步:
         1. 抽象出一个父类型
             共同的属性定义,集中到父类型的构造函数中
             共同的方法,集中到父类型的原型对象中
         2. 在子类型构造函数中借用父类型构造函数
              不能直接调用: this->window
             应该用call,将this替换为当前正在创建的新对象
               父类型构造.call(this,参数...)
         3. 让子类型原型对象继承父类型原型对象

  

       


 

猜你喜欢

转载自blog.csdn.net/Pony_18/article/details/82312907