JavaScript进阶十五(ES5中的继承问题)

本文详细讲解了如何使用call()函数在ES6之前实现组合继承,包括如何通过构造函数继承父类型属性和方法,以及各种继承方式的优缺点和适用场景。重点介绍了原型链继承的模拟以及通过原型对象实现方法的正确继承方式。
摘要由CSDN通过智能技术生成


一、继承父类方法

ES6之前并没有给我们提供extends继承,所以我们可以通过构造函数+原型对象模拟实现继承,被称为组合继承。

call()

调用这个函数,并且修改函数运行时的this指向 基本格式为:
fun.call(thisArg,arg1,arg2,...)

thisArg:当前调用函数this的指向对象
arg1,arg2…:传递的其他参数
call有两个作用:
1、call可以调用函数

<!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>
</head>
<body>
    <script>
        function fn(){
            console.log('haha');
        }
        fn.call();//结果为haha
    </script>
</body>
</html>

2、修改函数里的this指向

<!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>
</head>
<body>
    <script>
        //在未改变前,函数里的this指向window,现在可以使用call让函数里的this指向我们创建的对象obj
        function fn(x,y){
            console.log(this);
            console.log(x,y);
        }
        var obj = {
            name:'haha'
        }
        fn.call(obj,1,2);
    </script>
</body>
</html>

结果为:
在这里插入图片描述

1、借助构造函数继承父类型属性

通过call()把父类的this指向子类型的this,这样就可以实现子类型继承父类型的属性。

<!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>
</head>
<body>
    <script>
        //父构造函数
        function Father(uname,age){
            //this指向父构造函数的对象实例
            this.uname = uname;
            this.age = age;
        }
        //子构造函数
        function Son(uname,age,sex){
            //this指向子构造函数的对象实例
            //改变this指向
            Father.call(this,uname,age);
            this.sex = sex;
        }
        var son = new Son('haha',12,'女');
        console.log(son);
    </script>
</body>
</html>

在这里插入图片描述

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>
</head>
<body>
    <script>
        //父构造函数
        function Father(uname,age){
            //this指向父构造函数的对象实例
            this.uname = uname;
            this.age = age;
        }
        Father.prototype.money = function(){
            console.log('今日赚200元');
        }
        //子构造函数
        function Son(uname,age,sex){
            //this指向子构造函数的对象实例
            //改变this指向
            this.sex = sex;
            Father.call(this,uname,age);
        }
        Son.prototype = Father.prototype;
        var son = new Son('haha',12,'女');
        console.log(son);
        son.money();
    </script>
</body>
</html>

在这里插入图片描述
可以看出,此时的子构造函数对象实例中包括了父构造函数原型对象的money方法,而且可以调用money方法。
但是这种方法有一个缺点,我们可以给Son的原型对象增加一个方法,然后打印出父构造函数的原型对象看一看。

<!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>
</head>
<body>
    <script>
        //父构造函数
        function Father(uname,age){
            //this指向父构造函数的对象实例
            this.uname = uname;
            this.age = age;
        }
        Father.prototype.money = function(){
            console.log('今日赚200元');
        }
        //子构造函数
        function Son(uname,age,sex){
            //this指向子构造函数的对象实例
            //改变this指向
            this.sex = sex;
            Father.call(this,uname,age);
        }
        Son.prototype = Father.prototype;
        var son = new Son('haha',12,'女');
        Son.prototype.say = function(){
            console.log('hello');
        }
        console.log(Father.prototype);
    </script>
</body>
</html>

在这里插入图片描述
此时,我们会发现父构造函数的原型对象也包括了子构造函数原型对象中的say方法,这是因为我们在执行Son.prototype = Father.prototype;时,使Son的原型对象引用指向了父构造函数的原型对象,所以覆盖了Father.prototype,所以我们改变Son.prototype,Father.prototype也随之改变了。
(2)利用原型对象实现方法的继承
我们可以让子原型对象成为父构造函数的实例对象,这样子原型对象可以通过__proto__继承到父原型对象里的方法,且因为实例对象与原型对象的地址是不同的,所以给子原型对象增加方法时,也不会覆盖父原型对象。但是注意,要利用constructor将Son指回原来的构造函数。
代码示例为:

<!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>
</head>
<body>
    <script>
        //父构造函数
        function Father(uname,age){
            //this指向父构造函数的对象实例
            this.uname = uname;
            this.age = age;
        }
        Father.prototype.money = function(){
            console.log('今日赚200元');
        }
        //子构造函数
        function Son(uname,age,sex){
            //this指向子构造函数的对象实例
            //改变this指向
            this.sex = sex;
            Father.call(this,uname,age);
        }
        //子构造函数专门的方法
        Son.prototype = new Father();
        //如果利用对象的形式修改了原型对象,别忘了利用constructor指回原来的构造函数
        Son.prototype.constructor = Son;
        var son = new Son('haha',12,'女');
        Son.prototype.say = function(){
            console.log('hello');
        }
        console.log(son);
        console.log(Son.prototype);
        console.log(Father.prototype);
    </script>
</body>
</html>

在这里插入图片描述
图解如下:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值