一篇搞懂 面向对象!

什么是面向对象?

        程序中先用对象来保存现实中一个事物的属性和功能,然后再按需访问对象中保存的属性和   功能。
优点:便于大量数据的维护和使用。

面向对象三大特点:

  • 封装
  • 继承
  • 多态

封装

什么是封装?

 创建一个对象,集中保存现实中一个事物的属性和功能

如何封装一个对象,如何创建一个对象?

①用{ }直接创建对象

var 对象名={
          属性名属性值
                 ... ...
          方法名:function(){
                 ... this.属性名....
           }
    }
通过.操作符进行访问对象里的内容 
访问对象里的属性值:     对象名.属性名   
访问对象里的方法   :     对象名.方法名()

方法 vs 函数
相同:都是function
不同:独立于任何对象之外,单独存在的function,称为函数
           保存在对象内的function,称为方法

注:
对象中的函数不能直接获取对象的属性 要用 this.属性名访问
this 是每个函数中自带的,可以自动获得正在调用当前函数的 .前的对象 的关键词 
例如  :LiMing.interSelf()    在调用时.前是谁 this就指谁,这里指LiMing 相当于LiMing.sname
只要对象自己的方法内 想使用对象自己的属性,必须加“this.属性名”

//创建一个对象LiMing
var LiMing={
    sname:"Li Ming",
    sage:19,
    interSelf:function(){
        console.log(`我叫${sname}`) //报错sanme is not defined
        //对象自己的函数 访问对象自己的属性 报错 因为所有不加.的访问默认只能在作用域链(函数作用域 
          和全局作用域window)中查找变量,无权进入对象属性中查找  用this.属性名解决
        console.log( ` 我叫${this.sname} ,年龄 ${this.sage} ` )
    }
}
//获取李明的年龄
console.log(LiMing.sage); 
//请李明做自我介绍
LiMing.interSelf();
//李明长了一岁
LiMing.sage++;
//再获取李明的年龄
console.log(LiMing.sage);

② 用new Object( )创建;

     先用new Object()创建一个空对象
     为空对象强行添加新属性

// new Object()是 { } 的标准写法 , { }是简写
var LiMing = new Object();
LiMing.sname="Li Ming";
LiMing.sage=19;
LiMing.interSelf=function(){
                  ...this.sname...
                 }

 js中一切对象 底层都是关联数组!以下均可证明

  • 对象和关联数组一样 都是“名值对儿”的集合
  • 在对象访问成员属性(对象.sname)和关联数组中访问成员属性(arr["sage"])
    LiMing.sname  和 arr["sage"] 一样  (对象.属性名  访问  和数组[" "]访问 一样)
    LiMing.sname 会自动翻译为LiMing["sname"]    同样  arr["sage"] 可简写 arr.sage
  • 关联数组可以通过强行赋值的方式随时添加新元素,而对象也可以 不会报错
  • 访问关联数组中 不存在的位置 不会报错而是返回underfined 同样访问对象中一个不存在的属性也不会报错 返回underfined
  • 都可以用 for in 遍历每个对象中的属性  for ( kay in object ){ ${key} : object.[key]}
③ 用构造函数constructor创建;

前两种创建对象的方式适用于只创建一个对象的情况 ,而反复创建多个想同结构的对象时,代      码会很繁琐,且不便于维护,还占内存空间  

//假设创建多个学生对象
var student1 ={
    sname:"student1",
    sage:19,
    intrSelf:function(){
      console.log(`姓名 :${this.sname} , 年龄:${this.sage}`)
    }
}
var student2 ={
    sname:"student2 ",
    sage:20,
    intrSelf:function(){
      console.log(`姓名 :${this.sname} , 年龄:${this.sage}`)
    }
}
var student3 ={
    sname:"student3 ",
    sage:21,
    intrSelf:function(){
      console.log(`姓名 :${this.sname} , 年龄:${this.sage}`)
    }
}
var student4 = { .... }
//如果还用之前{ }的方式定义对象 会造成代码冗余 而且及其不便于修改和维护,那么我们就要用构造函数创建对象 来规避这个缺点

如果要反复创建多个相同结构的对象时,都要用构造函数

如何使用构造函数?
   ①定义一个构造函数来描述一类对象统一的结构
     function 类型名 (形参1,形参2){   //新对象有几个属性 构造函数上就要定义几个形参变量
        this.属性名=“形参1”,      //新对象中的每个属性的方法都要用this.定义
        this.属性名=“形参2”,
        this.方法名=function(){ ... this.属性名 ...},

      }
   ②反复用 new 调用构造函数,就会反复创建多个相同类型的对象
        用法: var 新对象 = new 类型名(属性值1,属性值2,...)

//用构造函数来定义 对象
function Student (sname,sage){
    this.sname = sname,
    this.sage = sage,
 // this.intrSelf = function(){ console.log(`姓名:${this.sname} , 年龄:${this.sage}`) },
}
//用new 调用构造函数 创建对象
var student1= new Student("Li Ming",19) //输出和 { } 创建的对象是一样的
console.log(student1)
//反复创建多个对象 就很便于维护
var student2= new Student("Zhang San",20) 
var student3= new Student("Li Si",20) 

首先,new 会创建一个新对象 
然后,调用构造函数时的实参值(属性1,属性2,...)会传给构造函数的形参变量
然后,构造函数中规定的所有属性和方法,都会被添加到新对象中
最后,new会返回新创建的对象 保存到=左边的变量里

那么new 是怎样执行的呢?(构造函数的原理)
①new创建一个新的空对象
②让新创建的子对象,自动继承构造函数的原型对象
③用新对象调用构造函数,此时的 构造函数里的this指向正在创建的新对象new,通过强行赋值的方式,将构造函数的所有属性和方法,强行添加到 正在创建的新对象中

问题:反复用构造函数创建多个对象 那么凡是在构造函数中的方法定义 每次创建一个新对象都要重复创建一遍这个方法 会造成占用内存  所以构造函数中不应该包含方法的定义 只包含属性的定义。

继承

因为构造函数只能重用代码结构,但是会浪费内存,所以构造函数不包含方法的定义
所以 今后所有对象中要使用的公共的方法的定义 要使用继承

什么是继承?

父对象中的成员,子对象无需重复创建就可以直接使用
既可以重用代码 ,又可以节约内存!

什么时候使用继承?

只要多个对象都需要公共的该方法定义(函数)时,就要用继承来实现

如何使用继承?

①找到所有子对象 共同的父对象 (原型对象:为将来所有子对象,保存共有特征的一个父对象)

  什么是原型对象?

    其实在 定义构造函数中都会附赠一个原型对象prototype(父对象),
    并且可以通过构造函数函数名.prototype访问到 该对象暂时为空
    new会让创建的子对象自动继承构造函数的原型对象
    new会自动设置 新创建的子对象._ _ proto_ _ = 构造函数.prototype

②将所有子对象公共的方法定义添加到共同的父对象
     构造函数名.prototype.公共方法名=function(){ ...  this.属性名 ...}。
③所有子对象因为继承关系 就可以直接使用父对象中的公共方法。
    当子对象调用原型对象上的公共方法时,现在子对象中找该方法,如果没有找到就会
    延着_ _proto_ _属性自动去原型对象中查找。
    所以原型对象中定义的公共方法(函数)里的this ,不是看定义在哪儿,而是谁调用这个方法
    this就指向谁 调用时 .前是谁this就指向谁   比如student1.interSelf()那么这里的this 就指向      student1。

// 用继承的方式定义对象
// 把构造函数里的方法删掉 加到原型对象中
function Student (sname,sage){
    this.sanme=sname;
    this.sage=sage;
}

//把孩子需要的公共函数 定义在原型对象上
Student.prototype.interSelf = function(){
         console.log(`姓名:${this.sname},年龄:${this.sage}`)   
         //这里的this 指向谁 要看谁调用的这个公共函数          
}

//调用构造函数 创建新的子对象
var student1 = Student("Li Ming",19);
var student2 = Student("Zhang San",20);
console.log( student1, student2)

//孩子在这里调用公共函数interSelf();
student1.interSelf();
student2.interSelf();

自有属性 和 共有属性

自有属性:保存在子对象内部,归该子对象独有的属性。 例如  sname sage属性

共有属性:保存在原型对象中,归多个子对象共有的属性。 例如 interSelf( )属性 

获取属性值时:自有属性和共有属性都可以通过 ”子对象.属性名“来访问。

修改属性值时:自有属性 可以通过 “子对象.属性名 = 新值” 来修改 student1.sname="xxx"
                         共有属性  只能用 “原型对象.属性名 = 新值” 来修改                                 Student.prototype.className="初一二班"

function Student (sname,sage){
    this.sname=sname;
    this.sage=sage;
}
Student.prototype.className="初一二班"
var student1 = new Student("Li Ming" ,19);
var student2 = new Student("Zhang San" ,20);
var student3 = new Student("Li Si" ,20);

//修改自有属性
student1.sname="李明"
//修改共有属性
Student.prototype.className="初二二班"

console.log(student1 ,student3 ,student3)

如果需要某种操作 但是原型对象上没有 我们其实可以自己添加 为这个类型的原型对象,添加一个自定义的共有函数  例如:经常需要对数组中元素求和

//Array是function Array(){...}的构造函数 所以创建数组时可以var arr = new Array() ;
//其实 [ ] 是new Array()的简写;
//所以 Array 也有原型对象  在原型对象中的方法数组可以直接调用 例如 arr.push() arr.sort()都是再原型对象中的
 
//向Array的原型对象上添加一个 sum()数组
Array.prototype.sum = function(){
    var total = 0;
    for ( var i = 0 ;i < this.length; i++){
        total+=this[i]
    }
    return total;
}
var arr1 = [1,2,3]
var arr2 = [5,6,7,8]
console.log(arr1.sum(), arr2.sum())
原型链  prototype chain

什么是原型链?

由多级父对象逐级继承,形成的链式结构,原型链保存着一个对象所有的属性和方法,控制着属性和方法的使用顺序先自有属性 再延原型链向父级查找 先找到那个就用那个

逐级继承    每个对象都有自己的原型链

  • 20
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值