面向对象

99 阅读2分钟

面向对象

概述

面向对象是一种编程思想(oop),它主要的核心就是抽取对应的对象(封装)(万物皆对象 ),调用对象的方法。里面的主要的思维就是找有对应方法的对象做对应的事情(调用对应的方法)。

面向过程与面向对象
面向过程 (关注于过程)

去餐馆吃饭

  • 出门
  • 去餐馆的路上
  • 进门点餐
  • 厨师炒菜
  • 服务员上菜
  • 吃饭
  • 买单
面向对象 (关注于对象)

去餐馆吃饭

  • 找餐馆这个对象

对象的创建

使用new 关键词

直接调用对应的构造函数 (ES3)
//构造函数 首字母大写
function Person(name,age){
	this.name = name //构造函数里面的this指向其构建的实例对象
	this.age = age
}
var person = new Person('张三',18)
调用class的constructor (ES6)
class Person{
	//constructor就是其构造函数
	constructor(name,age){
		this.name = name //constructor里面的this指向其构建的实例对象
		this.age = age
	}
}
var person = new Person('张三',18)
class和构造函数的区别
  • class采用了严格模式 不能重复声明一个名字,而构造函数没有采用严格模式可以重复声明
  • class 不会进行预编译和构造函数会进行预编译
  • 构造函数可以不使用new关键词调用,而class必须使用new关键词调用(不能使用new关键词会报错)
  • class 可以使用extends来实现继承 它可以继承静态属性
new关键词做了什么
  • 自动构建对象 (将构造的对象的原型指向构造函数的原型)
  • 自动执行构造函数 (将当前构建对象做为this传递 执行对应的构造函数)
  • 自动返回对象

使用工厂函数

批量生成对象,忽略细节
function factory(name){
	//手动构建对象
	var obj = {}
	//手动指定属性
	obj.name = name
	//手动返回对象
	return obj
}
var newObj = factory('jack')
工厂函数和构造函数的区别
  • 工厂函数批量生成 忽略细节
  • 构造函数一对一生成 关注细节

面向对象的三大特性

  • 封装 (抽取对应的名词为属性,动词为方法)
    示例

    有一只狗名字叫旺财,它会叫

    class Dog{
    	constructor(name){
    		this.name = name //名词抽取为属性
    	}
    	say(){
    		console.log(`${this.name}在叫`) //动词为方法
    	}
    }
    new Dog('旺财').say()
    
    练习

    页面上有一个按钮上显示内容为你好 点击更改你好为不好

    class Button { //按钮对象
        constructor(value) {
            this.value = value
            this.init()
        }
        init(){
            this.button = document.createElement('button') //按钮元素
            this.button.innerText = this.value //初始化指定显示内容
            document.body.append(this.button)
            this.handlerClick('不好')
        }
        //处理点击 this指向
        handlerClick(value) {
            //给按钮添加事件
            // 如果作为一个回调函数 或者是事件调用的函数里面的this绝对不会指向原本this 指向调用者的this
            let that = this
            this.button.addEventListener('click', function () {
                // this.innerText = value //里面的this 指向调用者
                that.button.innerText = value
            })
        }
    }
    new Button('你好')
    
  • 继承 (子类继承父类的非私有内容)
    class Animal{
        constructor(name){
            this.name = name
        }
        sayHello(){
            console.log('hello')
        }
    }
    class Person extends Animal{
        constructor(name,age){
            super(name) //调用父类的构造函数 里面的this会指向当前构建的实例
            this.age = age
        }
    }
    let person = new Person('张三',18)
    console.log(person.age)
    console.log(person.name) //继承父类的属性
    person.sayHello() //继承父类的方法
    
  • 多态 (基于继承关系 子类是父类的另一种形态体现)
    重写(子类重写父类的方法)
    class Animal {
        constructor(name) {
            this.name = name
        }
        sayHello = () => {
            console.log('hello')
        }
    }
    class Person extends Animal {
        constructor(name, age) {
            super(name) //调用父类的构造函数 里面的this会指向当前构建的实例
            this.age = age
        }
        //重写继承于父类的方法
        sayHello = () => {
            console.log('你好')
        }
    }
    let person = new Person('张三', 18)
    person.sayHello() //继承父类的方法 进行重写 调用自身重写的方法
    
    重载 (在一个类中 有俩个同名的方法 (通过参数个数及参数类型进行区分))

    重载在js中不存在 (js弱类型语句 不能强制指定类型,js的函数允许少传参及多传参,相同的变量在同一作用域内会产生覆盖)

面向对象Tab栏切换

基础切换
//构建Tab栏的类
class Tab{
    constructor(nav,content){
        this.nav = nav //导航栏
        this.content = content //内容
        this.activeIndex = 0 //激活的下标
        //执行处理点击事件的方法
        this.handlerClick()
    }
    //处理点击
    handlerClick(){
        //nav下面的内容添加点击
        [...this.nav.children].forEach((v,i)=>{
            v.addEventListener('click',()=>{
                this.activeIndex = i
                this.toggle()
            })
        })
    }
    //切换
    toggle(){
        //排他
        //将选中的添加选中效果 其他移除
        //移除所有的激活效果
        [...this.nav.children].forEach(v=>v.classList.remove('active'))
        //给对应的激活下标的添加激活效果
        this.nav.children[this.activeIndex].classList.add('active');
        //显示选中  隐藏未选中
        //将所有的内容全部隐藏
        [...this.content.children].forEach(v=>v.classList.add('hidden'))
        //显示激活的
        this.content.children[this.activeIndex].classList.remove('hidden')
    }
}
var nav = document.querySelector('.nav')
var content = document.querySelector('.content')
//实例化对象
new Tab(nav,content)
数据渲染生成
//构建Tab栏的类
class Tab {
    //传入大盒子  传入数据 [{title:'hello',content:"aa"}]
    constructor(wrap, data) {
        this.nav = wrap.querySelector('.nav') //导航栏
        this.content = wrap.querySelector('.content') //内容
        this.data = data ? data : [] //数据
        this.activeIndex = 0 //激活的下标
        this.init()
    }
    init() {
        //根据data生成对应的内容 
        //遍历解构获取对应的值
        this.data.forEach(({
            title,
            content
        }, i) => {
            this.nav.innerHTML += `
<li class=${this.activeIndex == i ? "active" : ""}>
${title}
</li>
`
            this.content.innerHTML += `
<div class=${this.activeIndex != i ? "hidden" : ""}> ${content}</div>
`
        })
        //执行处理点击事件的方法
        this.handlerClick()
    }
    //处理点击
    handlerClick() {
        //nav下面的内容添加点击
        [...this.nav.children].forEach((v, i) => {
            v.addEventListener('click', () => {
                this.activeIndex = i
                this.toggle()
            })
        })
    }
    //切换
    toggle() {
        //排他
        //将选中的添加选中效果 其他移除
        //移除所有的激活效果
        [...this.nav.children].forEach(v => v.classList.remove('active'))
        //给对应的激活下标的添加激活效果
        this.nav.children[this.activeIndex].classList.add('active');
        //显示选中  隐藏未选中
        //将所有的内容全部隐藏
        [...this.content.children].forEach(v => v.classList.add('hidden'))
        //显示激活的
        this.content.children[this.activeIndex].classList.remove('hidden')
    }
}
//实例化对象
new Tab(document.querySelector('.box'), [{
    title: "吃饭",
    content: "<b>吃饭</b>"
}, {
    title: "睡觉",
    content: "<i>睡觉</i>"
}, {
    title: "打豆豆",
    content: "<b>打豆豆</b>"
}])