18 面向对象

概述:

面向对象是一种编程思想(oop),面向对象相对于面向过程的一个抽取和简化。主要是以类来构建对象,以对象来存储对应的行为及属性,抽取对应的行为做为方法 ,抽取对应的属性做为属性。

1.对象:对象是一个整体,对外提供一些操作。

2.面向对象:使用对象时,只关注对象提供的功能,不关注其内部细节。比如电脑——有鼠标、键盘,我们只需要知道怎么使用鼠标,敲打键盘即可,不必知道为何点击鼠标可以选中、敲打键盘是如何输入文字以及屏幕是如何显示文字的。总之我们没必要知道其具体工作细节,只需知道如何使用其提供的功能即可,这就是面向对象。

3.JS的对象组成:方法 和 属性

在JS中,有函数、方法、事件处理函数、构造函数,其实这四个都是函数,只是作用不同。函数是独立的存在,方法属于一个对象,事件处理函数用来处理一个事件,构造函数用来构造对象。

面向对象核心 万物皆对象(所有的内容都可以抽取为一个对象)关键点:找有这个行为的对象去完成这个行为

关键词:找有这个行为的对象去完成这个行为

面向对象和面向过程

面向过程以过程为核心
例(去饭店吃饭)

1.先找饭店

2.找服务员点餐

3.等待上菜

4.吃饭

5.结账

面向对象以对象为核心
  1. 我找饭店 (我这个对象 饭店这个对象)

  2. 结账 吃饭 点餐属于我的行为

  3. 饭店提供的相关内容就是饭店的行为

对象的构建

调用new关键词,去执行对应的构造函数来构建对象

通过类来构建对象(构造器)es6
class Person{
constructor(username){
       this.name=username;//this 指向当前的对象实例
  }
}
var person = new Person('jack')
通过改造函数来构建(es3)
//以构造函数构建 首字母大写
function Dog(name){
   this.name = name //函数里面的this指向它的调用者 在new的时候指向对应的对象实例
}
var dog  = new Dog('阿黄')

例子也可以看出来,this即表示当前函数的调用者是谁,但是在一种情况下不是的,就是使用new 来创建对象时,this并不是指向调用者的,在后面会有说明。

window是全局对象,属于window的全局属性和全局方法:

 

 

 

 

 

 

面向对象特点

1、抽象:抽指把核心的东西抽出来,把与我们要解决的问题有关的东西拿出来摆在面前

2、封装:让使用对象的人不考虑内部实现,只考虑功能使用 把内部的代码保护起来,只留出一些个api接口供用户使用

3、继承:就是为了代码的复用,从父类上继承出一些方法和属性,子类也有自己的一些属性

4、多态:实际上是不同对象作用与同一操作产生不同的效果。多态的思想实际上是把“想做什么”和“谁去做“分开

对象的组成

1、方法 函数:过程、动态的

2、属性 变量:状态、静态的

this 当前的方法属于谁就是谁

例如点击事件里的this,其实就是触发事件的那个dom对象的onclick方法里的this,当然是人家自己咯

再比如说一个函数里的this,这个函数都属于window的一个方法,当然里面的this也是window咯

还有哦,不要在系统对象上面添加属性和方法,这样不太好

那么在谁身上加呢?在object这个对象身上,别的date呀array呀,这些对象都是有一些个好玩的功能的,

object也就自己最强大的一个功能就是,没有功能—— 这样咱们就可以随意给他加属性和方法而不用去想会不会覆盖了

 

通过改造函数构建做了什么操作
  • 自动构建对象

  • 手动设置属性

  • 自动返回对象

 

通过工厂模式来构建对象

通过构造函数来生成对象,将重复的代码提取到一个函数里面,避免写大量重复的代码。这样可以在需要这个对象的时候,就可以简单地创建出来了。

  • 手动构建对象

  • 手动设置属性

  • 手动返回对象

//以工厂模式来构建
//工厂里面要传入对应的属性 返回对应的对象(不能区分类型)
function factory(name){
   //Object是最大的对象 手动构建对象
   var obj = new Object()
   //手动给obj设置相关的属性
   obj.name = name
   //手动返回对应的对象
   return obj
}
//调用
var obj = factory('旺财')
var obj1 = factory('jack')
console.log(obj,obj1);
工厂模式的特性
  • 可以构建所有的对象

  • 在构建对象的时候会忽略细节

  • 构建出来的对象都是Object(instanceof全部指向Object)

console.log(obj instanceof Object);//true
console.log(obj1 instanceof Object);//true

 

也就说会有两种问题:1. 创建对象没有用到new 感觉心里空落落的 2. 方法都不一样的话太占据空间。

 

面向对象的的三大特征

  • 封装 (将对应的行为抽取为方法 属性抽取为属性)

  • 继承 (子类继承父类的属性和方法)

  • 多态 (继承关系的体现 重写(子类重写父类的方法) 重载(在一个类有俩个同名的方法 js不允许 没有重载))

 

封装示例

示例: 有一个猫会喵喵叫 很胖800斤 吃的很多 名字叫咪咪

属性: 体重800 名字咪咪

方法: 喵喵叫 吃的很多

继承及对应的重写

class Person{
   constructor(){
       // var sex = '男'
       this.name = 'jack'
       this.say = ()=>{
           console.log('哈哈哈哈');
      }
  }
}
class Son extends Person{
   constructor(age){
       super() //调用Person的constructor
       this.age = age
       //重写
       this.say = ()=>{
           console.log('嘻嘻嘻嘻');
      }
  }
}
var son = new Son()
console.log(son);//name say age
son.say() //嘻嘻嘻嘻

面向对象tab栏切换

属性:上面的tab栏 下面的显示框

方法: 上面的点击事件 切换下面的显示栏的方法

//构建一个类
class Tab{
   constructor(nav,contents){
       this.nav = nav //上边的点击栏
       this.contents = contents //下面的切换的内容
       this.selectIndex = 0
       this.handlerClick()
  }
   //切换的方法
   toggle(selectElement){
       //选中内容变成对应的样式为selected 其他排他
       Array.from(this.nav).forEach((item)=>{
           item.className = ''
      })
       selectElement.className = 'selected';
       // this.nav[this.selectIndex].className = 'selected'
       //下面切换内容 样式为show
       Array.from(this.contents).forEach((item)=>{
           item.className = ''
      })
       //根据你传入的元素来查找下标
       let i = Array.from(this.nav).findIndex((v)=>{
           return v == selectElement
      })
       this.contents[i].className = 'show'
  }
   //点击事件处理
   handlerClick(){
       let _this = this
       Array.from(this.nav).forEach((item,i)=>{
          item.onclick = ()=>{
           // _this.selectIndex = i
            _this.toggle(item)
          }
      })
  }
}

面向对象拖拽实现

// 拖拽实现
// 属性 包含拖拽盒子的大盒子 拖拽的盒子 盒子的坐标位置
class Touch {
   constructor(outerBox, move) {
       this.outerBox = outerBox //包含的盒子
       this.move = move //移动的盒子
       this.point = { //坐标位置
           x: parseInt(this.getStyle(move).left) || 0,
           y: parseInt(this.getStyle(move).top) || 0
      } //基础坐标为0,0
       this.handlerDown()
  }
   //获取样式的方法
   getStyle(element) {
       return window.getComputedStyle ? window.getComputedStyle(element, '') : element.currentStyle
  }
   //按下
   handlerDown(){
       this.move.onmousedown = (e)=>{
           e = e || window.event
           //获取第一次按下的位置
           let currentX = e.offsetX
           let currentY = e.offsetY
           //调用移动的方法
           this.handlerMove(currentX,currentY)
           //调用弹起的方法
           this.handlerUp()
      }
  }
   //弹起
   handlerUp(){
       document.onmouseup = ()=>{
           this.outerBox.onmousemove = null
      }
  }
   //移动
  handlerMove(currentX,currentY){
        //给大盒子添加移动事件
        this.outerBox.onmousemove = (e) => {
           e = e || window.event
           //大盒子在页面上的位置
           let { x, y } = this.getPagePoint(this.outerBox)
           //获取移动的位置 - 大盒子在页面上的位置 - 当前按下位置
           let { targetX, targetY } = {
               targetX: e.pageX - x - currentX,
               targetY: e.pageY - y - currentY
          }
           let { maxX, maxY } = {
               maxX: this.outerBox.offsetWidth - this.move.offsetWidth,
               maxY: this.outerBox.offsetHeight - this.move.offsetHeight
          }
           //区间判断
           if (targetX < 0) {
               targetX = 0
          }
           if (targetX > maxX) {
               targetX = maxX
          }
           if (targetY < 0) {
               targetY = 0
          }
           if (targetY > maxY) {
               targetY = maxY
          }
           //将对应的位置设置进去
           this.point = { x: targetX, y: targetY }
           this.setMovePoint()
      }
  }
   setMovePoint() {
       //设置
       this.move.style.left = this.point.x + 'px'
       this.move.style.top = this.point.y + 'px'
  }
   getPagePoint(element) {
       let x = 0
       let y = 0
       while (element.offsetParent) {
           x += element.offsetLeft
           y += element.offsetTop
           element = element.offsetParent
      }
       return { x, y }
  }
}

基于面向的拖拽实现放大镜

//放大镜功能和区间拖拽的实现有类似
class Magnifier extends Touch {
   constructor(smallBox, moveBox, bigBox, bigImage) {
       //传给父类
       super(smallBox, moveBox) //outerBox move
       this.bigBox = bigBox
       this.bigImage = bigImage
       this.handlerEnter()
       this.handlerLeave()
  }
   handlerEnter() {
       this.outerBox.onmouseenter = () => {
           this.move.style.display = 'block'
           this.bigBox.style.display = 'block'
           this.init()
           //调用移动的方法
           this.handlerMove(this.move.offsetWidth / 2, this.move.offsetHeight / 2)
      }
  }
   handlerLeave() {
       this.outerBox.onmouseleave = () => {
           this.move.style.display = 'none'
           this.bigBox.style.display = 'none'
      }
  }
   init() {
       //将移动的move的大小初始化
       this.move.style.width = this.outerBox.offsetWidth / (this.bigImage.offsetWidth / this.bigBox.offsetWidth) + 'px'
       this.move.style.height = this.outerBox.offsetHeight / (this.bigImage.offsetHeight / this.bigBox.offsetHeight) + 'px'
  }
   setMovePoint() {
       //根据对应的坐标来设置对应的位置
       //设置
       this.move.style.left = this.point.x + 'px'
       this.move.style.top = this.point.y + 'px'
       //设置大图片的位置
       // 外面的盒子/移动的盒子 = 大的图片/大的盒子
       // 350 / ? = 800 / 540
       // 350 = (800 / 540 ) * ? ==> ? = 350 / (800 / 540)
       // 150 / 350 == 大的图片移动多少 ?/800
       //   150 / 350 = ?/800 ===> ? = 150/350*800
       let x = this.point.x / this.outerBox.offsetWidth * this.bigImage.offsetWidth * -1
       let y = this.point.y / this.outerBox.offsetHeight * this.bigImage.offsetHeight * -1
       //设置大图片的定位
       this.bigImage.style.left = x + 'px'
       this.bigImage.style.top = y + 'px'
  }
}
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

原文地址:http://www.cnblogs.com/hofenglang/p/16823364.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性