• [JavaScript]面对对象编程,构造函数,原型


    目录

    面对对象编程

    面对对象和面向过程

    优缺点

    面向对象的三大特性

    构造函数

    体现封装性

    原型

    原型

    constructor 属性

    对象原型

    原型继承

    属性继承借用父构造函数实现继承属性

    函数的call()方法

    ​编辑

    方法继承原型继承继承方法

    注意:

    组合式继承属性和方法组合继承

    原型链


    面对对象编程

    面对对象和面向过程

           🏆 //面向对象与面向过程,是解决问题的两种思路

    //面向过程:先分析问题中的步骤,马上将分出来的步骤封装成函数,再按顺序依次调用即可解决问题

    //面向对象:先分析问题中的步骤,再将步骤划分不同的不同主体上,最的将顺序调用主体上方法

    1. //早晨起床上学
    2. //面向过程
    3. /*
    4. //起床
    5. function getUp(){}
    6. //洗澡
    7. function wash(){}
    8. //吃饭
    9. function eat(){}
    10. //去上学
    11. function toscholl(){}
    12. getUp()
    13. wash()
    14. eat()
    15. */
    16. //面向对象
    17. let stu = {
    18. getUp: function () { },
    19. //洗涑
    20. wash: function () { },
    21. //吃饭
    22. eat: function () { },
    23. //去上学
    24. toscholl: function () { }
    25. }
    26. stu.getUp()
    27. stu.wash()
    28. stu.eat()

    优缺点

    面向过程

     优点:执行效率更高

     缺点:当一个项目很大的时候,维护很困难,功能扩展几乎是没有

    //面向对象

    // 优点:对于应该后期维护,与功能扩展相对于面向过程更容易

    // 缺点:执行效率没有面向过程高

    面向对象的三大特性

            //面向对象的三大特性:

    //1.封装:严格的书写类,将方法与方法中的属性,封装到对象上(数据与操作数据的方法必须依附于一个主体)

    //2.多态:多种形态,根据参数的个数不同,参数的类型不同,可以调用不同的方法

    //3.继承:一个类继承另一个类

    //提示:

    //Js并不是纯正的面向对象语言,面向对象的三大特性,封装与继承体现的会多一点

    构造函数

    体现封装性

    🏆  封装是面向对象思想中比较重要的一部分,js面向对象可以通过构造函数实现的封装。

            // 同样的将变量和函数组合到了一起并能通过 this 实现数据的共享,所不同的是借助构造函数创建出来的实例对象之间是彼此不影响的

            // 总结:

            // 1. 构造函数体现了面向对象的封装特性

            // 2. 构造函数实例创建的对象彼此独立、互不影响

    1. function Person(uname, age) {
    2. this.uname = uname
    3. this.age = age
    4. this.sing = function () {
    5. console.log('唱歌')
    6. }
    7. }
    8. // new
    9. const ldh = new Person('刘德华', 58)
    10. // console.log(ldh)
    11. const zxy = new Person('张学友', 59)
    12. // console.log(zxy)
    13. // ldh.sing()
    14. // zxy.sing()
    15. //构造函数里面的方法会存在浪费内存的问题

            // 封装是面向对象思想中比较重要的一部分,js面向对象可以通过构造函数实现的封装。

    💎构造函数方法很好用,但是 存在浪费内存的问题

    原型

    原型

            //        🏆 利用原型对象实现方法共享

            //  构造函数通过原型分配的函数是所有对象所 共享的。

            //  JavaScript 规定,每一个构造函数都有一个 prototype 属性,指向另一个对象,所以我们也称为原型对象

            //  这个对象可以挂载函数,对象实例化不会多次创建原型上函数,节约内存

            //  💎我们可以把那些不变的方法,直接定义在 prototype 对象上,这样所有对象的实例就可以共享这些方法。

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

    💎js规定:如果要给构造函数添加方法不要再构造函数内部添加最好的方法就 是给构造函数的原型对象添加方法

    1. function Star(uname, age) {
    2. this.uname = uname
    3. this.age = age
    4. }
    5. console.log(Star.prototype)//返回一个对象
    6. //🏆每个构造函数 都有一个属性「prototype」属性的值是一个对象原型对象
    7. //💎js规定:如果要给构造函数添加方法不要再构造函数内部添加最好的方法就 是给构造函数的原型对象添加方法
    8. Star.prototype.sing = function () {
    9. console.log('我会唱歌')
    10. }
    11. const ldh = new Star('刘德华', 18)
    12. const zxy = new Star('张学友', 19)
    13. console.log(ldh.sing === zxy.sing)//true
    14. ldh.sing()
    15. zxy.sing()

    constructor 属性

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

            // 作用:该属性指向该原型对象的构造函数, 简单理解,就是指向我的爸爸,我是有爸爸的孩子

            //🏆 constructor属性的作用

            // 使用场景:

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

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

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

    1. // function Star(name, age) {
    2. // this.name = name
    3. // this.age = age
    4. // }
    5. // Star.prototype = {
    6. // sing: function () { console.log('唱歌') },
    7. // dance: function () { console.log('跳舞') }
    8. // }
    9. // const ldh=new Star('刘德华',78)
    10. // console.log(ldh);
    11. // //构造函数的原型对象被重新赋值,constructor此时不是Star,而是新的Object
    12. // console.log(ldh.__proto__.constructor===Star);//false
    1. function Star(name) {
    2. this.name = name
    3. }
    4. Star.prototype = {
    5. // 我们可以在修改后的原型对象中,添加一个 constructor 指向原来的构造函数。
    6. constructor: Star,
    7. sing: function () { console.log('唱歌') },
    8. dance: function () { console.log('跳舞') }
    9. }
    10. const ldh = new Star('刘德华', 78)
    11. console.log(ldh);
    12. console.log(ldh.__proto__.constructor === Star);//true
    13. console.log(Star.prototype.constructor)//指向 Star

    构造函数创建实例对象

    对象原型

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

    // 之所以我们对象可以使用构造函数 prototype  原型对象的属性和方法,

    // __proto__

    //就是因为对象有 __proto__ 原型的存在。

    // 💎注意:

    // __proto__ 是JS非标准属性

    // [[prototype]]和__proto__意义相同

    // 用来表明当前实例对象指向哪个原型对象prototype

    // __proto__对象原型里面也有一个 constructor属性,指向创建该实例对象的构造函数

    原型继承

    属性继承借用父构造函数实现继承属性

    //🏆子构造函数继承父构造的属性

    1. //🏆子构造函数继承父构造的属性
    2. function Product(name, price) {
    3. this.name = name;
    4. this.price = price;
    5. console.log(this);//this是f1,因为call改变了this指向
    6. }
    7. function Food(name, price) {
    8. //借用父构造函数将Product函数当成普通函数在调用
    9. //
    10. Product.call(this, name, price);
    11. this.category = 'food';
    12. }
    13. // 实例化food构造函数
    14. const f1 = new Food('rice', 6)
    15. // expected output: "cheese"
    16. console.log(f1)

    函数的call()方法

            //🏆 cal1()可以改变函数里面的this指向 函数名.cal1(对象)

            // 函数名.call(对象,函数里面的参数,函数里面的参数)

            //通过 var声明的全局变量相当于给 window对象添加属性

            //函数相当于给window对象添加的方法

    1. function f(x, y, z) {
    2. console.log(this, x, y,z);
    3. }
    4. const obj = {
    5. unname: '张三'
    6. }
    7. f.call(obj, 10, 20, 30)//this变成了obj

    控制台输出截图

    方法继承原型继承继承方法

            //🏆子构造函数继承父构造的方法

    1. function Product(name, price) {
    2. this.name = name;
    3. this.price = price;
    4. // console.log(this);//this是f1,因为call改变了this指向
    5. }
    6. // 给Product 构造函数的原型对象添加方法
    7. Product.prototype.sayHello = function () {
    8. console.log('hello!!!');
    9. }
    10. function Food(name, price) {
    11. //借用父构造函数将Product函数当成普通函数在调用
    12. //
    13. Product.call(this, name, price);
    14. this.category = 'food';
    15. }
    16. // Food.prototype = Product.prototype
    17. // 将实例化的父构造函数 的实例化对象 赋值给 子构造函数的原型对象
    18. //可以避免改变子构造函数的原型对象,父元素的原型对象也会改变
    19. Food.prototype = new Product()
    20. Food.prototype.sss = function () {
    21. console.log('我是food里的方法');
    22. }
    23. // 实例化food构造函数
    24. const f1 = new Food('rice', 6)
    25. // expected output: "cheese"
    26. console.log(f1)
    27. f1.sss()

    注意:

    1.如果使用Food.prototype = Product.prototype  ,会出现改变子构造函数的原型对象,父元素的原型对象也会改变

    Food.prototype = Product.prototype示例图

     2.如果使用 Food.prototype=new Product()

    不会修改父元素的原型对象的方法,原因是,new出来的Product()实例化对象 作为子元素的原型对象,新增的方法在旧方法的原型外部

    Food.prototype=new Product()图示例

     

    组合式继承属性和方法组合继承

            //🏆组合式继承:借用构造函数继承(继承属性)+原型链继承(继承方法)

    继承属性:子构造函数中使用函数call方法,调用父构造函数,传入(this,参数)

    继承方法:

    1. function Product(name, price) {
    2. // this.name = name;
    3. // this.price = price;
    4. // console.log(this);//this是f1,因为call改变了this指向
    5. }
    6. // 父元素的原型对象的方法
    7. function Food(name, price) {
    8. //借用父构造函数将Product函数当成普通函数在调用
    9. // Product.call(this, name, price);
    10. // this.category = 'food';
    11. }
    12. // 父元素原型对象增加方法
    13. Product.prototype.sayHello = function () {
    14. console.log('hello');
    15. }
    16. Food.prototype=new Product()//之所以不会修改父元素的原型对象的方法,原因是,new出来的Product()实例化对象既包含属性和方法,只是属性没有传参,
    17. // Food.prototype = Product.prototype
    18. // Food.prototype = new Product().__proto__
    19. // 对子元素原型对象增加方法
    20. Food.prototype.dance = function () {
    21. console.log('跳舞');
    22. }
    23. const s1 = new Food('周杰伦', 90)
    24. console.log(s1);
    25. s1.sayHello()
    26. s1.dance()
    27. const f1 = new Product('周杰伦', 90)
    28. console.log(f1);
    29. f1.sayHello()
    30. f1.dance()

    原型链

            //     🏆    基于原型对象的继承使得不同构造函数的原型对象关联在一起,并且这种关联的关系是一种链状的结构,我们将原型对

            // 象的链状结构关系称为原型链

            // 🏆原型链-查找规则

            // ① 当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性。

            // ② 如果没有就查找它的原型(也就是 __proto__指向的 prototype 原型对象) ③ 如果还没有就查找原型对象的原型(Object的原型对象) ④ 依此类推一直找到 Object 为止(null) ⑤ __proto__对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线

            // 💎可以使用 instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上

            // 判断实例对象和构造函数之间的关系

            // 通过的方式是,判断构造函数.prototype是否在实例对象的原型链上

    1. function Person() { }
    2. let p1 = new Person();
    3. function Mobile() { }
    4. let m1 = new Mobile();
    5. console.log(p1 instanceof Person);//true
    6. console.log(m1 instanceof Mobile);//true
    7. console.log(p1 instanceof Mobile);//false

  • 相关阅读:
    数据库系统原理与应用教程(041)—— MySQL 查询(三):设置查询条件
    数字化新零售营销模式如何落地?数字化新零售营销功能推荐
    WebGPU入门
    构建新纪元:Gradle中Kotlin插件的配置全指南
    【基础知识】从FT到FFT
    Leetcode—66.加一【简单】
    javaee之黑马旅游网2
    anaconda3最新版安装|使用详情|Error: Please select a valid Python interpreter
    k8s--基础--05--环境搭建--准备工作
    影响光源的因素
  • 原文地址:https://blog.csdn.net/wusandaofwy/article/details/126443454