JavaScript-0825

面向对象概述

面向对象属于编程思想。重点在于所有的事情考虑都需要以对象的角度出发。与面向对象对应的就是面向过程

前面所使用的对象对他的理解是一种数据类型。对象中可以存在很多的属性,属性又区分名称与值。对象下每个属

性的值 可以是任意数据类型,如果属性值是字符串、数字、布尔、数组、对象就可以表示出一些静止的属性。属

性值也可以使用函数(函数代码是可以运行的),所以当属性值为函数 可以表示出一种动作。所以对象可以表示出静

止的信息也可以表达出行为。所以对象可以用于描述个体信息

例如一辆车就是一个个体,但是车不会凭空产生。会根据设计稿制造出来,设计稿就好比一个模板,设计稿编程语

言来看就是"类" js中可以叫做构造函数(function)。

车是一个个体对象。车的轮子 也是对象。对象与对象直接是存在联系

面向过程:所有的事情都是自己来处理的 。例如做饭 需要自己逐步完成过程

面向对象:使用多个对象,对象与对象直接产生联系,例如做饭 可以找保姆 下达指令

标准面向对象思想是先有类在有对象,类是对很多相似的个体进行抽象化归类所得到的一个模板

面向对象(OOP)特性:封装、继承、多态(多种形态,身份可以切换)

创建对象的四种方式

字面量

let person = {
    name:'杜思聪',
    age:18,
    money:-100000,
    run:function(){
        console.log(this.name+' running');
    }
}
console.log(person.name);
console.log(person.run());
console.log(person)
/*
    字面量方式缺陷
    1、如果需要一个类似的对象 完整的代码需要在写一遍 麻烦
    2、当前对象 无法确定属于哪一种归类的对象
    字面量方式创造对象使用频率非常高 在数据交互时,根本不关心对象是什么类型 关心的是数据
*/

内置构造函数

// 在js语言中内置存在很多的构造函数 例如Number、Array、RegExp、Object等 内置中最大的构造函数为Object
let obj = new Object();
obj.name = '刘智鹏';
obj.age = 20;
obj.like = ['js','html','css'];
console.log(obj);
/*
    实例化内置的构造函数缺点与字面量方式一样
*/ 

工厂函数

// 1、使用工厂函数获取对象
// 工厂函数就是一个普通函数 可以返回对象
// function createObject() {
//     let obj = new Object();
//     obj.name = '刘智鹏';
//     obj.age = 20;
//     obj.like = ['js', 'html', 'css'];
//     return obj
// }
// createObject()
// createObject()
// 2、使用工厂函数传递参数控制对象属性值
function createObject(name, age, like = ['js', 'html', 'css']) {
    let obj = new Object();
    // 左边表示obj下存在name属性 值为参数name变量的值
    obj.name = name;
    obj.age = age;
    obj.like = like;
    return obj
}
console.log(createObject('leo', '31'));
console.log(createObject('zs',18));

自定义构造函数(重点)

1、函数多面性

// 1、函数的多面性
// 1.1、普通函数
function fn(){
    console.log('普通函数')
}
fn();
// 1.2、函数也是对象
// fn对象调用say属性并且赋值
fn.say = '能说话';
console.log(fn.say)
// 1.3、函数也是构造函数
console.log(new fn())

2、自定义构造函数使用

// 2、自定义构造函数
        // 一个function 在被创造时就已经决定了该如何使用,普通函数一般使用小驼峰命名 构造函数一般使用大驼峰命名
        function Person(){
            console.log('person构造函数代码被执行')
        }
        // 构造函数 需要使用必须与new关键字配置  只要实例化对象 构造函数中的代码会自动执行
        let p = new Person();

3、new时系统所做的操作

 // 3、new时系统所做的操作
function Dog(){
    // 1、先以当前构造函数创造一个对象  可以理解为 let obj = new Object
    // 2、将this指向创造的对象 可以理解为 let this = obj;
    // 3、将构造函数中的代码自动运行起来
    // 4、自动将结果返回 return this;
}

let d = new Dog();
console.log(d)

4、构造函数中this

// 4、构造函数中this
function Cat(){
    console.log(this)
    this.leg = 4;
}
let c = new Cat();
console.log(c);

5、使用构造函数传递参数控制对象

 // 5、使用构造函数传递参数
function Car(brand,price){
    // 当执行 59行代码 new对象是 构造函数中this 就表示bm对象
    this.brand = brand;
    this.price = price;
    this.start = function(){
        console.log(this);
        console.log('启动')
    }
}
// 在new构造函数传递的参数与普通函数一样也会进行形参赋值
let bm = new Car('bmw','300000');
console.log(bm);
bm.start();
// new 构造函数时如果没有参数 可以省略(),作为构造函数使用 千万别手动的return(可以在属性值为函数的代码中return)

原型

构造函数的缺点

1、测试代码

function Computer(cpu, memerySize, diskSize) {
    this.cpu = cpu;
    this.memerySize = memerySize;
    this.diskSize = diskSize;
    this.openBrower = function () {
        console.log(this.cpu)
        console.log('看电影')
    }
}

let c1 = new Computer('i5 7200', 8, 512);

let c2 = new Computer('I5', 16, 512);

2、内存图

构造函数中直接this设置属性为函数时会导致内存空间浪费。

原型

原型三句话

1、每一个构造函数天生具备属性prototype,并且属性值指向的是一个对象(原型对象,也是由系统分配)
2、每一个实例对象天生具备一个属性"__proto__",属性值指向到构造函数的原型(原型被所有的实例对象共享)
3、每一个原型天生具备属性constructor 反向指向到构造函数

原型中三者的关系

function Person(name){
    this.name = name;
}
// 现在Person 属于Function的实例对象
// let sum = new Function(); 
console.log(Person instanceof Function)
console.log(typeof Person)
//只要创建了一个函数系统就自动的分配了原型对象
console.log(Person.prototype);

let p1 = new Person('李四');
console.log(p1)
// 查看对象下__prpto属性
console.log(p1.__proto__)
let p2 = new Person('王五');
// 构造函数的原型 被所有的实例对象共享
console.log(p2.__proto__ == p1.__proto__);

console.log(Person.prototype == p1.__proto__);//true


console.log(Person.prototype.constructor == Person)
//千万别使用对象.__proto__操作到原型 这样虽然功能可以实现 但是不合理 需要操作原型 就使用构造函数来操作

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EDGZLvNL-1661419310487)(/1661409098337.png)]

原型链

function Dog(){
    this.type = 'single dog';
}
// 系统自动为Dog构造函数生成的原型对象
console.log(Dog.prototype);
// Dog的原型对象是系统自动以Object构造函数new出来的对象  所以Dog的原型 也有原型
console.log(Dog.prototype instanceof Object);
//  查看Dog原型的原型 Dog.prototype表示Dog构造函数的原型  
console.log(Dog.prototype.__proto__)
// null  Dog.prototype.__proto__.__proto__
console.log(Dog.prototype.__proto__.__proto__)

let ls = new Dog();

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-agxw1XXJ-1661419310488)(/1661412683546.png)]

对象属性使用规则

访问规则

function Person(leg = 2) {

            this.leg = leg;

            this.eyes = 2;
        }
        // 在Person的原型上添加eat方法
        Person.prototype.eat = function () {
            console.log(this.leg)
            console.log('eat')
        }
        // 原型上添加属性
        Person.prototype.zui = 1;
        Person.prototype.leg = 2;
        let p1 = new Person();
        console.log(p1)
        //获取当前对象下存在的属性
        console.log(p1.eyes);//2
        //获取当前对象下不存在 但是原型上存在的属性 先在当前对象下寻找属性 没找到 到原型上寻找(自动),如果找到了就直接使用
        console.log(p1.zui); 
        // 获取当前对象以及对应原型上都不存在的属性  先在当前对象下寻找,没找到 到原型上寻找,原型上也没有 就继续到原型的原型上寻找  找到了就直接用
        console.log(p1.toString);
        // 顺着原型链都没有找到这个属性最后就是undefined
        console.log(p1.abc);//undefined

赋值规则

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

        Person.prototype.leg = 2;

        let p = new Person('lei');
        // 修改当前对象下存在的属性
        p.name = 'change';
        // 修改当前对象下不存在 但是原型上有的属性,
        // 当修改对象下的属性时不论这个属性是否存在 永远是修改的当前对象 不可能修改到原型
        p.leg = 1;
        // 千万不要写下面的代码 要修改原型 就使用构造函数
        // p.__proto__.leg = 2;
        console.log(p)

总结:

1、当读取对象下的属性时,会按照原型链一层一层寻找,任何一层找到了就直接使用 否则到null都还没找到最后得到undefined 读取原型上的属性时不要手动使用_proto_

2、当修改对象下的属性时不论这个属性是否存在 永远是修改的当前对象 不可能修改到原型

面向对象改造选项卡

1、初版面向对象

<!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>
        .container {
            width: 600px;
            height: 400px;
            border: 10px solid #333;
            margin: 30px auto;
            display: flex;
            flex-direction: column;
        }

        .header {
            height: 40px;
            display: flex;
            line-height: 40px;
        }

        .header div {
            flex: 1;
            background-color: hotpink;
            text-align: center;
            font-size: 36px;
            color: white;
        }

        .header .active {
            background-color: orange;
        }

        .content {
            display: none;
        }
    </style>
</head>

<body>
    <div class="container">
        <div class="header">
            <div class="active">热卖</div>
            <div>精品</div>
            <div>推荐</div>
        </div>
        <div class="body">
            <div class="content" style="display: block;">1</div>
            <div class="content">2</div>
            <div class="content">3</div>
        </div>

    </div>
</body>

</html>
<script>
    function Tab() {
        
        
    }
    // Tab的原型上添加init方法实现特效的初始化
    Tab.prototype.init = function(){
        // 实现具体逻辑
        let headrs = document.querySelectorAll('.header>div');
        let contents = document.querySelectorAll('.body>.content');
        headrs.forEach((dom,index)=>{
            dom.addEventListener('click',function(){
                // 将所有的div active样式移除
                headrs.forEach(item=>item.className = '');
                // 为当前的添加样式
                this.className = 'active';
                // 将所有的content 设置为隐藏
                contents.forEach(content=>content.style.display='none');
                // 当前对应的content显示
                contents[index].style.display = 'block'
            })
        })

    }

    let t = new Tab();
    t.init();
</script>

2、面向对象版选项卡

function Tab(headrs,contents) {
        // 使用对象下的属性保存 数据
        this.headrs = headrs;
        this.contents = contents;
        // 手动调用初始化 避免 使用者 每次获取到对象还需要手动调用init
        this.init();     
    }
    // Tab的原型上添加init方法实现特效的初始化
    Tab.prototype.init = function(){
        // 此时的this还是表示着Tab的对象
        let _this = this;
        // 实现具体逻辑
        this.headrs.forEach((dom,index)=>{
            dom.addEventListener('click',function(){
                // 将所有的div active样式移除
                _this.headrs.forEach(item=>item.className = '');
                // 为当前的添加样式
                this.className = 'active';
                // 将所有的content 设置为隐藏
                _this.contents.forEach(content=>content.style.display='none');
                // 当前对应的content显示
                _this.contents[index].style.display = 'block'
            })
        })
    }

    new Tab(document.querySelectorAll('.header>div'),document.querySelectorAll('.body>.content'));
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

goto_w

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值