构造函数的继承与,类的继承 、原型链 、call(),apply(),bind()的区别

本文探讨了JavaScript中的构造函数继承、类继承以及原型链的概念。通过call()方法实现属性继承,利用prototype进行方法继承以避免内存浪费。类继承通过extends关键字和super关键字实现,同时强调了super关键字必须在this之前使用。原型链通过prototype对象优化了内存使用,__proto__属性连接了构造函数和实例对象。此外,还区分了call(), apply(), bind()在改变this指向上的不同应用。" 107226043,8344471,格式字符串漏洞攻防实战,"['安全', 'C语言编程', '漏洞利用', '软件安全', '缓冲区溢出']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

***构造函数继承

属性继承:利用call()方法改变超类型构造函数this指向

  // 属性继承
        function Father(U_name, age, sex) {
            this.U_name = U_name;
            this.age = age;
            this.sex = sex

            console.log(this); //  this指向Son
        }

        function Son(U_name, age, sex) {
            Father.call(this, U_name, age, sex) //改变Father this指向 

        }
        let son = new Son('张三', 18, 'sex')
        console.log(son);

 这时候我们看到打印结果:通过Son构造函数实力出来的对象已经拿到了Father构造函数里的属性

但是这种方式也有一个缺点 就是继承不了超类型构造函数里边的方法;

 function Father(U_name, age, sex) {
            this.U_name = U_name;
            this.age = age;
            this.sex = sex
        }
        Father.prototype.sing = function() {
            console.log('lalalala');
        }

        function Son(U_name, age, sex) {
            Father.call(this, U_name, age, sex)

        }
        let son = new Son('张三', 18, 'sex')
        console.log(son);

 

 那如果要把超类型构造函数里边的方法也继承过来就可以用下边这种方法:

方法继承:利用原型对象prototype继承方法

   function Father(U_name, age, sex) {
            this.U_name = U_name;
            this.age = age;
            this.sex = sex
        }
        Father.prototype.sing = function() {
            console.log('lalalala');
        }

        function Son(U_name, age, sex) {
            Father.call(this, U_name, age, sex)

        }
        Son.prototype = new Father()
        Son.prototype.constructor = Son


        let son = new Son('张三', 18, '男')
        son.sing()
        console.log(son);

这个原理就是让子类构造函数的原型对象等于超类型构造函数实例出来的对象,通过子类型构造函数的原型对象下的对象原型可以找到超类型构造函数实例对象的对象原型,继而访问它里面的方法。

***类的继承

1.利用 extends 关键字继承

语法:class 子类 extendx 父类

  // 父类
        class Father {
            constructor(age, sex) {
                this.age = age
                this.sex = sex
            }
            sing() {
                console.log('lalalalala');
            }
        }
        // 子类
        class Son extends Father {}
        let obj = new Son(12, '男')
        obj.sing
        console.log(obj);

2.利用super访问父类属性方法

super()相当于Parent.prototype.constructor.call(this)  将父类this指向子类


        class Father {
            constructor(age, sex) {
                this.age = age
                this.sex = sex
            }
            sing() {
                console.log(this.age * this.sex);
            }
        }

        class Son extends Father { //  extends   子类可以调用父类的方法
            constructor(age, sex, weight) {
                super(age, sex) //访问超类型构造函数
                this.weight = weight
            }
            run() {
                console.log(this.age - this.sex);
            }
        }
        let obj = new Son(22, 20, 150)
        obj.sing() //  440
        obj.run() //  22

!!! : 在这里要特别注意 super关键字一定要在this之前 因为子类没有自己的this对象,而是继承父亲的this对象。如果不调用super,子类就得不到this对象。

***原型链

prototype  原型对象

当我们通过构造函数实例多个对象时,构造函数都会开辟一个新的空间去存放这些方法,就会催在很严重的内存浪费,那这个时候就出现了一个叫做prototype原型对象的东西,专门开辟一个空间去存放这些共有属性和方法,因为他是一个对象,所以称它为对象原型。每一个构造函数都有prototype这个属性,那么通过构造函数实例出来的对象都会共享这个方法。

具体语法如下:

 通过打印台可以看到 实例出来的对象拿到了这个方法,构造函数的prototype里也存在这个方法。

--proto--

对象都会有一个属性__proto__,指向构造函数的prototype原型对象,之所以我们对象可以使用构造函数prototype原型对象的属性和方法,就是因为有__proto__原型的存在。那我们看下构造函数的prototype是不是指向实例对象的__proto__.

 显然返回值是true  这也能说通为什么实例对象能拿到构造函数的prototype里的方法了。

constructor

当然每一个构造函数里的方法肯定不止一种 但是我们要一个一个去通过下边这种方式去写的话就太麻烦了

 // 添加方法
        Person.prototype.sing = function() {
            console.log('lalalala');
        }
        Person.prototype.jump = function() {
            console.log('jumpjumpjumpjump');
        }
        Person.prototype.sleep = function() {
            console.log('huhuhuuhuhuhu');
        }

那我们可以通过下边去给他添加多个方法

 Person.prototype = {
                sing: function() {
                    console.log('lalalalalal');
                },
                jump: function() {
                    console.log('jumpjumpjumpjump');
                },
                sleep: function() {
                    console.log('huhuhuhuhuhuhuhuhu');
                }
            }

但是又会出现一个问题  他的constructor 指向的不是他的构造函数了,因为构造函数的prototype是一个对象,我们上边的写法等于是给他重新赋值,那他之前的里边的东西就会被覆盖掉。

 这时候我们就要让他的constructor 重新指向他的构造函数

  Person.prototype = {
                constructon: Person,
                sing: function() {
                    console.log('lalalalalal');
                },
                jump: function() {
                    console.log('jumpjumpjumpjump');
                },
                sleep: function() {
                    console.log('huhuhuhuhuhuhuhuhu');
                }
            }

   他就指回他的构造函数了。那么contructor的作用就是记录该对象是那个构造函数实例化出来的。

上边说到每个对象都有一个对象原型__proto__ 那构造函数的原型对象prototype肯定也有一个,那他就指向大对象Object的原型对象Object.prototype,那Object.prototype也是一个对象,他也有对象原型__proto__,那在往上找就是null 。这就是原型链。

 

 call(),apply(),bind()的区别

call() 一般用于继承 他可以改变this指向 后边传入参数

   function Father(age, sex) {
            this.age = age
            this.sex = sex

        }


        function Son(age, sex, weight) {
            Father.call(this, age, sex) //将Father  this指向 Son
            this.weight = weight
        }
        var zap = new Son('zhangsan', 32, 120)
        console.log(zap);

apply()一般用于数组,也可以改变this指向 第一个参数和call()一样 改变this指向,但是后边的参数是数组

 bind()  和call()bind() 一样改变this指向,最大的区别就是不会调用函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值