美文网首页
浅谈javascript面向对象三大特点,通过面向对象看原型原型

浅谈javascript面向对象三大特点,通过面向对象看原型原型

作者: Fairy_妍 | 来源:发表于2022-02-09 21:10 被阅读0次

    面向对象

    面向对象的三大特点:封装、继承、多态。

    先使用一个个的对象结构集中存储现实中事物的属性和功能。 然后,再按需使用不同对象中的不同属性和功能。这就是面向对象编程。

    面向对象使其便于大量数据的管理维护

    一、封装

    • 封装就是创建一个对象,集中保存现实中一个事物的属性和功能。
    • 将零散的数据封装进对象结构中,极其便于大量数据的管理维护。
    • 今后,只要使用面向对象思想开发时,第一步都是先封装各种各样的对象结构备用。

    封装对象三种方式:

    1. 直接使用{}。访问时使用对象名.属性名对象名.方法名()

      var lilei={
        sname:"Li Lei",//姓名
        sage:11,//年龄
        intr:function(){
          console.log(`I'm ${this.sname}, I'm ${this.sage}`)
        }
      }
      
    2. 使用new Object()

      var lilei = new Object();  // 创建空对象
      lilei.sname = 'Li Lei';
      lilei.intr = function(){
        console.log(`I'm ${this.sname}`)
      }
      

      该方法揭示了js语言底层最核心的原理:js中所有对象底层都是 关联数组

    关联数组和对象
    a. 关联数组和对象的存储结构都是 键值对 的形式
    
    b. 访问成员时的方法都是`对象名/数组名['成员名']`,简写`对象名/数组名.成员名`
    
    c. 强行给不存在的位置或属性赋值不会报错,且添加新属性。
    
    d. 强行访问不存在的位置/属性的值不会报错
    
    e. 可以用for...in..循环遍历`for(var 属性名 in 对象名/数组名){...}`
    
    1. 使用构造函数

      使用前两种方法创建对象,如果想创建多个结构相同的对象时,代码会重复很多,不便维护。解决办法:构造函数-描述同一类型的所有对象的统一结构的函数。

      // 使用构造函数步骤1:定义构造函数
      function Student(name, age) {
          this.name = name
          this.age = age
          this.intr = function(){
              console.log(`I'm ${this.name}, I'm ${this.age}`)
          }
      }
      // 步骤2:使用构造函数反复创建多个对象
      var lilei = new Student('lilei', 20)
      var liumei = new Student('liumei', 18)
      

    总结

    1. 使用new时,此处new做了4件事:①创建一个新的空对象;②设置子对象的__proto__属 性,指向构造函数的原型对象(下文详细讨论继承);③调用构造函数时,将构造函数的this指向新new出来的对象;同时在构造函数内通过强行赋值方式,为新对象添加规定的属性和方法。④返回新对象的地址保存到左侧变量中。

    2. 此处出现了this的2种情况:①obj.fun()调用obj中的fun方法时,fun中的this指向obj对象。②new Fun()时,Fun中的this指向新new出来的对象。

    二、继承

    在上面的构造函数中,每次new一个新的对象时,都要给新对象赋值一个intr的function,每次定义function时相当于new Function操作,每次都会在内存中开辟新的空间保存这个function,实际上的funtion的内容都是一样的,没必要每次都新创建,造成内存浪费。

    解决方法:子对象都需要的相同功能和属性值可以用继承解决。

    继承:父对象中的成员,子对象无需重复创建,就可直接使用。

    js中继承都是通过原型对象实现的。

    原型

    • 原型对象: 替所有子对象集中保存共有的属性和方法的父对象。

    • 何时使用原型对象:当多个子对象有相同属性或功能时,就可以将相同的属性和方法集中定义在原型对象中。

    • 如何创建原型对象:无需额外操作。在定义构造函数时,会自动生成空的原型对象

    • 如何访问原型对象:构造函数中都有一个自带属性prototype,指向自己的原型对象。

    • 如何实现继承:在上面封装模块案例中,通过new构造函数可以实现子对象继承构造函数的原型对象。new使得子对象的__proto__属 性,指向构造函数的原型对象。

    • 如何向原型对象中添加共有属性:直接对其需要的属性赋值:构造函数.prototype.属性名= 属性值构造函数.prototype.方法名 = function(){...}

      关于原型和原型链及继承会在这篇文章中详述:js原型、原型链及继承

    使用了原型对象后,在子对象访问属性或方法时,js引擎会优先在子对象内部查找自有属性或方法。当子对象中没有时,js引擎会沿着__proto__属性去父对象(原型)上查找。若原型上存在该方法或属性,就直接使用,和使用自身的属性方法一样。这个沿着原型查找方法和属性的链路即为原型链。原型链是由多级父对象逐级继承形成的链式结构。

    总结:构造函数中方法可以定义在原型对象中,为所有子对象共有。

    function Student(name, age) {
        this.name = name
        this.age = age
    }
    // 将intr方法定义在构造函数的原型对象上
    Student.prototype.intr = function(){
        console.log(`I'm ${this.name}, I'm ${this.age}`)
    }
    var lilei = new Student('lilei', 20)
    lilei.intr();   //I'm lilei, I'm 20
    var liumei = new Student('liumei', 18)
    liumei.intr();  //I'm liumei, I'm 18
    

    此处出现了this的第③种情况:在原型对象共有的方法中使用了this,此处不看定义只看调用,此时谁调用这个公共的方法,this就指向谁。

    总结以上三种this情况:谁调用,this就指向谁。

    内置类型

    • 内置类型:ES标准中规定的,浏览器已实现的,我们可以直接使用的类型。
    • 目前已有11种类型:StringNumberBooleanArrayDateRegExpFunctionObjectErrorMathglobal/window。(在es6种新增了Symbol类型)
    • 类型:每种类型需要有2部分组成:①构造函数:负责创建该类型的子对象(可以被new的);②原型对象:负责为该类型所有子对象集中保存公共的方法和属性。
    • 所有上面的11种类型中有9种由构造函数和原型对象组成。Math和global/window实际上只是一个内置对象。

    三、多态

    多态指的是同一个函数在不同情况下表现出不同的状态

    一般认为多态包括2种

    • 重载overload:同一个函数,参数列表不同时,执行的逻辑不同,效果不同。
    • 重写overrider:在子对象中有与父对象重名的方法。当父对象中的该方法不好用时,可以在子对象中定义同名方法,来覆盖父对象中的该方法

    如下例:toString()的方法调用会产生多种不同的结构

    function Student(sname,sage){
        this.sname=sname;
        this.sage=sage;
    }
    var lilei=new Student("Li Lei",11);
    console.log(lilei);     // Student {sname: "Li Lei", sage: 11}
    var arr=[1,2,3];
    var now=new Date();
    console.log(lilei.toString());  // [object Object]
    console.log(arr.toString());    // 1,2,3
    console.log(now.toString());    // Wed Feb 09 2022 18:17:05 GMT+0800 (中国标准时间)
    

    发生这样的原因在于:①lilei的toString方法调是用的Object.prototype上的方法;②数组的toString方法在Array.prototype上重新定义了toString方法,所有没有再往上查找Object.prototype上的toString方法;③Date类型跟Array同理,对自己类型的原型对象进行了重写,没有继续往上查找toString方法。④以Array类型为例,查找顺序是:arr -> Array.prototype -> Object.prototype -> null。

    所以如果Student不想用Object.protoype上的tostring方法,则可以在自己原型上重写

    Student.prototype.toString=function(){
        return `my name is ${this.sname}`
    }
    console.log(lilei.toString());  // my name is Li Lei
    

    面向对象总结:

    1. 封装:创建对象两种方式。
    2. 继承:所有子对象共用的属性值和方法,都要 放在构造函数的原型对象中
    3. 多态:重写——只要觉得从父对象继承来的成员 不要用,都在子对象中重写同名成员。

    相关文章

      网友评论

          本文标题:浅谈javascript面向对象三大特点,通过面向对象看原型原型

          本文链接:https://www.haomeiwen.com/subject/hhdgkrtx.html