面向对象编程

面向过程编程

面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候再一个一个依次调用就可以了
面向过程:就是按照我么分析好的步骤,按照步骤解决问题

蛋炒饭

  1. 准备米饭
  2. 炒鸡蛋(倒入鸡蛋翻炒)
  3. 炒胡萝卜、香肠
  4. 把米饭、鸡蛋、胡萝卜一起翻炒

优点:
性能高,适合跟硬件联系比较紧密的东西,比如单片机,采用面向过程编程

缺点:
不灵活,复用性差

面向对象编程

把事务分解成为一个个对象,对象之间分工合作
在这里插入图片描述
优点:
易维护,易复用,易拓展,由于面向对象有封装继承,多态的特性,设计的系统更加灵活,易于维护

缺点:
性能低

面向对象的特性

  • 封装性
  • 继承性
  • 多态性

构造函数

封装时面向对象思想中比较重要的一部分,js面向对象可以通过构造函数来实现封装
把公共的属性和方法抽取封装到构造函数里面来实现数据的共享,这样创建的实例对象就可以使用这些属性和方法

        // 构造函数实现封装
        function Person(name, age) {
            this.name = name
            this.age = age
            this.sayHi = function () {
                console.log("HI~")
            }
        }

        const zs = new Person('张三', 18)
        const ls = new Person('李四', 19)
        console.log(zs)
        console.log(ls)
        console.log(zs === ls)  //false

        /* 
        总结:
        构造函数体现了面向对象的封装特性
        构造函数实例创建的对象彼此独立,互不影响
        */

        // 构造函数实现封装有个问题   存在浪费内存的问题  (构造函数中函数会多次创建,占用内存)
        console.log(zs.sayHi === ls.sayHi)  //false  两个函数不一样

原型对象

js规定,每一个构造函数都有一个prototype属性,指向另一个对象,我们称为原型对象
使用场景
可以解决:构造函数封装时函数(方法)会多次创建,占用内存的问题
原型对象可以挂载
函数
,对象实例化不会多次创建原型对象里的函数,节约内存

    实例对象可以直接访问原型对象中的函数
    执行过程:先找实例对象的属性或函数,找不到会再找原型对象中属性或函数
        // 构造函数实现封装
        function Person(name, age) {
            this.name = name
            this.age = age
            // this.sayHi=function(){
            //     console.log("HI~")
            // }
        }
        // console.log(Person.prototype)
        Person.prototype.sayHi = function () {
            console.log("HI~")
        }
        console.log(Person.prototype)
        const zs = new Person('张三', 18)
        const ls = new Person('李四', 19)
        zs.sayHi()
        ls.sayHi()
        console.log(zs.name)
        console.log(zs.sayHi === ls.sayHi)  //true

        // 实例对象可以直接访问原型对象中的函数
        // 执行过程:先找实例对象的属性或函数,找不到会再找原型对象中属性或函数

        const arr = new Array()
        console.log(Array.prototype)//原型对象
        // arr.filter()

原型对象-this指向

构造函数和原型对象中this都指向 实例化的对象

        // 构造函数this指向  实例对象
        function Person(name, age) {
            this.name = name
        }

        // 原型对象this指向
        Person.prototype.sayHi = function () {
            console.log('~HI')
            console.log(this)  //指向实例对象张三
        }
        const zs = new Person("zs", 18)
        zs.sayHi()
        /*
         注意:
         箭头函数不能做构造函数,因为箭头函数里没有this
         原型对象里面的函数如果需要用到this,也不要用箭头函数 
        */

constructor属性

每个原型对象里面都有个constructor属性(constructor构造函数)

作用:该属性指向该原型对象的构造函数

使用场景:

如果有多个对象的方法,我们可以给原型对象采取对象形式赋值

但是这样会覆盖构造函数原型对象原来的内容,这样修改后的原型对象 constructor 就不再指向当前构造函数了

此时我们可以再修改后的原型对象中,添加一个constructor指向原来的构造函数

        function Person(name) {
            this.name = name
        }

        // constructor属性在原型对象里面
        console.log(Person.prototype)

        // constructor属性指向原型对象的构造函数
        console.log(Person.prototype.constructor === Person)  //true

        // 使用场景
        // Person.prototype.sing= function(){
        //     console.log("我会唱歌")
        // }
        // Person.prototype.dance= function(){
        //     console.log("我会跳舞")
        // }
        Person.prototype = {
            // 手动设置constructor 指向Person
            constructor: Person,
            sing() {
                console.log("我会唱歌")
            },
            dance() {
                console.log("我会跳舞")
            }
        }
        console.log(Person.prototype)

__proto__属性

对象都会有一个属性__proto__指向构造函数的prototype原型对象

之所以我们对象可以使用构造函数prototype原型对象的方法,就是因为对象有__proto__的存在

        function Person(name) {
            this.name = name
        }

        // 实例对象里有__proto__属性
        const zs = new Person('zs')
        console.log(zs)

        // __proto__ 指向原型对象
        console.log(zs.__proto__ === Person.prototype)//true


        // 注意
        // prototype 原型对象  __proto__ 原型
        // __proto__ 非标准属性  尽量不要去修改它 否则影响性能

原型、原型对象和实例对象之间的关系

在这里插入图片描述

案例

    // const arr = new Array()
    // arr.filter

    // 给数组扩展求最大值方法 和求和方法

    const arr = [1, 2, 3];
    arr.reverse()
    // console.log(arr)  //[3, 2, 1]

    // 需要扩展
    // arr.max()  //3
    // arr.sum()   //6

    // 数组扩展求最大值/最小值
    Array.prototype.max = function () {
      // this  原型对象里的this指向实例对象
      return Math.max(...this)
    }

    console.log(arr.max())
    console.log([3, 6, 7].max())
    console.log([22, 55, 44].max())

    // 数组扩展求和方法
    const arr2 = [1, 2, 3]
    Array.prototype.sum = function () {
      // 求和
      return this.reduce((prev, current) => prev + current, 0)
    }

    console.log(arr2.sum())
    console.log([3, 5, 6].sum())

原型链

proto属性链状结构称为原型链
原型链为对象成员的查找机制提供了一个方向,或者是一条路线

查找机制

  • 当访问一个对象成员(属性/方法)时,首先查找这个对象自身有没有该成员(属性/方法)
  • 如果没有就查找它的原型对象(也就是proto指向的prototype原型对象)
  • 如果还没有就查找原型对象的原型对象(Object的原型对象)
  • 依次类推一直找到Object为止(null)

在这里插入图片描述

// __proto__属性链状结构称为原型链

function Person(name) {
	this.name = name
}

// 实例对象
const zs = new Person('张三');
// zs.sayHi= function(){
//     console.log("实例对象的方法")
// }
// zs.sayHi()
// Person原型对象
// Person.prototype.sayHi=function(){
//     console.log("Person原型对象的方法")
// }
// zs.sayHi()
// Object原型对象
// Object.prototype.sayHi=function(){
//     console.log("Object原型对象的方法")
// }
// zs.sayHi()
// null
console.log(zs.sayHi)  //undefined
// zs.sayHi()  //zs.sayHi is not a function

instanceof运算符

作用:用来检测构造函数.prototype是否存在于实例对象原型链上

实例对象.instanceof 构造函数

原型继承

继承是面向对象编程的另一个特性,龙生龙,凤生凤 老鼠的儿子会打洞描述的正是继承的含义

有些公共的属性和方法可以写到父级身上,子级通过继承也可以使用这些属性和方法

js中大多是借助原型对象实现继承的特性

const person ={
	eyes: 2,
	eat:function(){
		console.log("我会吃饭")
	}
}

function Man(){
            
}


function Woman(){
          
}

// 封装  抽取公共部分
// 把男人和女人公共的部分抽取出来放到person对象里面
// 继承 通过原型对象实现继承
// 把男人 女人原型对象赋值为person对象
Man.prototype =person
const zs = new Man()
console.log(zs)
Woman.prototype = person
const xl = new Woman()
console.log(xl)
// 3.使用字面量对象实现继承会有问题
// 女人会生孩子
// 男人和女人同时使用了同一个对象,根据引用类型的特点,他们指向同一个对象,修改一个就会都影响
Woman.prototype.baby =function(){
	console.log("我会生孩子")
}
console.log(xl)
console.log(zs)

解决

构造函数实例化对象继承,new每次都会创建一个新的对象

// 解决  男人和女人不要使用同一个对象,但是不同对象里面包含相同的属性和方法
//  使用  构造函数实例化对象继承,new每次都会创建一个新的对象
        
function Person (){
	this.eyes=2
}
Person.prototype.eat = function(){
	console.log("我会吃饭")
}

console.log(new Person()===new Person())  //false
function Man(){

}

Man.prototype = new Person()
Man.prototype.constructor = Man


function Woman(){
          
}
Woman.prototype = new Person()
Woman.prototype.constructor  =Woman

const zs = new Man()

const xl = new Woman()

Woman.prototype.baby =function(){
	console.log("我会生孩子")
}
console.log(xl)
console.log(zs)

模态框封装案例

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .modal {
            width: 400px;
            height: 100px;
            border: 1px solid #333;
            position: fixed;
            top: 0;
            bottom: 0;
            left: 0;
            right: 0;
            margin: auto;
        }

        .modal .header {
            padding: 10px;
            display: flex;
            justify-content: space-between;
        }

        .modal .body {
            text-align: center;
        }
    </style>
</head>

<body>
    <button class="del">删除</button>
    <button class="login">登录</button>
    <!-- <div class="modal">
          <div class="header"><span>温馨提示</span><i>x</i></div>
          <div class="body">你没有删除权限操作</div>
    </div> -->
    <script>
        // 面向对象写插件   模态框
        // 构造函数  把模态框封装一个构造函数Model 每次new都会产出一个模态框  所以点击不同的按钮 就是在做new模态框实例化
        // 模态框有什么功能   显示   关闭    构造函数Model的原型对象上

        //  1.Modal构造函数
        // 公共属性  标题title   提示信息内容message  可以设置默认参数
        function Modal(title = "", message = "") {
            //   创建modal模态框盒子
            // 创建div标签  modal
            // modal盒子内部填充2个div标签并且修改文字内容
            this.modalBox = document.createElement('div')
            this.modalBox.className = 'modal'
            this.modalBox.innerHTML = `
            <div class="header"><span>${title}</span><i>x</i></div>
            <div class="body">${message}</div>
            `
            console.log(this.modalBox)
        }


        // new Modal("温馨提示","你没有删除权限操作")
        // new Modal("友情提示","你还没有登录")

        // open
        //   写到构造函数的原型对象上
        // 把刚才创建的modalBox添加到页面body标签中
        // open打开的本质就是 把创建的标签添加到页面中
        // 点击按钮 实例化对象,传入对应的参数 执行open方法
        Modal.prototype.open = function () {
            // 注意不能用箭头函数
            // 把刚才创建的modalBox添加到页面body标签中
            // bug: 判断页面中有没有modal 有就移除 没有就添加
            const box = document.querySelector('.modal')
            box && box.remove()
            document.body.append(this.modalBox)
            // 要等到盒子显示出来 就可以绑定点击事件
            this.modalBox.querySelector('i').addEventListener('click', () => {
                console.log(1)
                // 这个地方要用到箭头函数  this指向实例对象
                this.close()
            })

        }

        document.querySelector('.del').addEventListener('click', function () {
            const del = new Modal("温馨提示", "你没有删除权限操作")
            del.open()
        })


        document.querySelector('.login').addEventListener('click', function () {
            const login = new Modal("友情提示", "你还没有登录")
            login.open()
        })

        // close
        // 写到构造函数的原型对象上
        // 把刚才创建的modalBox 从页面body标签中删除
        // 需要注意x关闭按钮在模态框里面
        // 页面显示这个模态框就要绑定事件
        // 页面显示模态框在open里面   绑定关闭事件也要写到open方法里面
        Modal.prototype.close = function () {
            this.modalBox.remove()
        }
    </script>
</body>

</html>

函数递归

递归:递归就是一种函数调用自身的操作(函数内部自己调用自己–递归–这个函数就是递归函数)

递归函数的作用和循环效果类似

递归一定要有退出条件return,没有就会出现 ‘栈溢出’

function fn(){
   fn()
}

案例

// 函数内部自己调用自己  ---递归

// 使用函数递归打印3句话
let i = 1;
function fn() {
	console.log(`我是第${i}句话`)
	if (i >= 3) return
	i++
	fn()  //递归
}
// 10递归.html:16 Uncaught RangeError: Maximum call stack size exceeded
// fn() 

// 练习:利用递归函数实现setTimeout 模拟setInterval效果
// 页面每隔一秒输出当前的时间 
// 输出当前时间可以使用new Date().toLocalString()

function timer() {
	const time = new Date().toLocaleString()
	console.log(time)
	setTimeout(timer, 1000)
}

timer()

// 1+2+3+4+5+....+n

function fn1(n) {
	if (n === 1) {
	return 1
	}
	return n + fn1(n - 1)
}

fn1(6)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值