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

发布于:2023-01-10 ⋅ 阅读:(432) ⋅ 点赞:(0)

目录

面对对象编程

面对对象和面向过程

优缺点

面向对象的三大特性

构造函数

体现封装性

原型

原型

constructor 属性

对象原型

原型继承

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

函数的call()方法

​编辑

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

注意:

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

原型链


面对对象编程

面对对象和面向过程

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

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

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

        //早晨起床上学
        //面向过程
        /*
        //起床
        function getUp(){}
        //洗澡
        function wash(){}
        //吃饭
        function eat(){}
        //去上学
        function toscholl(){}
        getUp()
        wash()
        eat()
        */

        //面向对象
        let stu = {
            getUp: function () { },
            //洗涑
            wash: function () { },
            //吃饭
            eat: function () { },
            //去上学
            toscholl: function () { }
        }
        stu.getUp()
        stu.wash()
        stu.eat()

优缺点

面向过程

 优点:执行效率更高

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

//面向对象

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

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

面向对象的三大特性

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

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

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

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

//提示:

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

构造函数

体现封装性

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

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

        // 总结:

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

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

       function Person(uname, age) {
            this.uname = uname
            this.age = age
            this.sing = function () {
                console.log('唱歌')
            }
        }
        // new
        const ldh = new Person('刘德华', 58)
        // console.log(ldh)
        const zxy = new Person('张学友', 59)
        // console.log(zxy)
        // ldh.sing()
        // zxy.sing()
        //构造函数里面的方法会存在浪费内存的问题

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

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

原型

原型

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

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

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

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

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

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

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

        function Star(uname, age) {
            this.uname = uname
            this.age = age
        }
        console.log(Star.prototype)//返回一个对象

        //🏆每个构造函数 都有一个属性「prototype」属性的值是一个对象原型对象
        //💎js规定:如果要给构造函数添加方法不要再构造函数内部添加最好的方法就 是给构造函数的原型对象添加方法
        Star.prototype.sing = function () {
            console.log('我会唱歌')
        }
        const ldh = new Star('刘德华', 18)
        const zxy = new Star('张学友', 19)
        console.log(ldh.sing === zxy.sing)//true
        ldh.sing()
        zxy.sing()

constructor 属性

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

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

        //🏆 constructor属性的作用

        // 使用场景:

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

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

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

        // function Star(name, age) {
        //     this.name = name
        //     this.age = age

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

构造函数创建实例对象

对象原型

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

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

// __proto__

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

// 💎注意:

// __proto__ 是JS非标准属性

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

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

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

原型继承

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

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

        //🏆子构造函数继承父构造的属性
        function Product(name, price) {
            this.name = name;
            this.price = price;
            console.log(this);//this是f1,因为call改变了this指向
        }

        function Food(name, price) {
            //借用父构造函数将Product函数当成普通函数在调用
            // 
            Product.call(this, name, price);
            this.category = 'food';
        }

        // 实例化food构造函数
        const f1 = new Food('rice', 6)
        // expected output: "cheese"
        console.log(f1)

函数的call()方法

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

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

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

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

        function f(x, y, z) {
            console.log(this, x, y,z);
        }

        const obj = {
            unname: '张三'
        }
        f.call(obj, 10, 20, 30)//this变成了obj

控制台输出截图

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

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

 
        function Product(name, price) {
            this.name = name;
            this.price = price;
            // console.log(this);//this是f1,因为call改变了this指向
        }
        // 给Product 构造函数的原型对象添加方法
        Product.prototype.sayHello = function () {
            console.log('hello!!!');
        }

        function Food(name, price) {
            //借用父构造函数将Product函数当成普通函数在调用  
            // 
            Product.call(this, name, price);
            this.category = 'food';
        }

        // Food.prototype = Product.prototype  
        // 将实例化的父构造函数 的实例化对象 赋值给 子构造函数的原型对象  
        //可以避免改变子构造函数的原型对象,父元素的原型对象也会改变
        Food.prototype = new Product()

        Food.prototype.sss = function () {
            console.log('我是food里的方法');
        }

        // 实例化food构造函数
        const f1 = new Food('rice', 6)
        // expected output: "cheese"
        console.log(f1)
        f1.sss()

注意:

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

Food.prototype = Product.prototype示例图

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

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

Food.prototype=new Product()图示例

 

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

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

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

继承方法:

  function Product(name, price) {
            // this.name = name;
            // this.price = price;
            // console.log(this);//this是f1,因为call改变了this指向
        }
        // 父元素的原型对象的方法
        function Food(name, price) {
            //借用父构造函数将Product函数当成普通函数在调用
            // Product.call(this, name, price);
            // this.category = 'food';
        }


        // 父元素原型对象增加方法
        Product.prototype.sayHello = function () {
            console.log('hello');
        }

        Food.prototype=new Product()//之所以不会修改父元素的原型对象的方法,原因是,new出来的Product()实例化对象既包含属性和方法,只是属性没有传参,

        // Food.prototype = Product.prototype
        // Food.prototype = new Product().__proto__

        // 对子元素原型对象增加方法
        Food.prototype.dance = function () {
            console.log('跳舞');
        }

        const s1 = new Food('周杰伦', 90)
        console.log(s1);
        s1.sayHello()
        s1.dance()


        const f1 = new Product('周杰伦', 90)
        console.log(f1);
        f1.sayHello()
        f1.dance()

原型链

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

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

        // 🏆原型链-查找规则

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

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

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

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

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

      function Person() { }
        let p1 = new Person();
        function Mobile() { }
        let m1 = new Mobile();
        console.log(p1 instanceof Person);//true
        console.log(m1 instanceof Mobile);//true

        console.log(p1 instanceof Mobile);//false


网站公告

今日签到

点亮在社区的每一天
去签到