js里面继承及6种继承

继承的核心机制

要理解继承必须理解原型对象 和原型链的关系和指向问题
 一个构造函数由构造函数本身和构造函数的原型对象两个部分组成 ,也就是构造函数有一个隐藏的属性__proto__,指向构造函数的原型对象。当构造函数被实例化时,把构造函数中的所有属性和方法拷贝到实例当中,同时,这个__proto__属性也会被拷贝,当访问实例对象当中的属性或方法时,会先从实例本身找,如果找到了,就会使用实例中的这个属性或方法;如果没有找到,就会通过__proto__属性中保存的地址找到原型对象,再从原型对象里找这个属性或方法。

以上就是原型链的核心机制,属性搜索机制。
  构造函数和、实例和原型对象三者之间的关系可以用下图表示
  在这里插入图片描述

  function Star(uname, age) {
            this.uname = uname;
            this.age = age;
            // this.sing = function() {
            //     console.log("我想唱歌");

            // }
        }
        Star.prototype.sing = function() {
                console.log("我想唱歌");

            }
            //一般情况下,我们的公共属性定义在构造函数里面,公共的方法放在原型对象身上
        var ldh = new Star("刘德华", 19);
        ldh.sing();
        console.log(ldh); //对象身上系统的自己添加一个 __proto__指向我们构造函数的原型对象
        console.log(ldh.__proto__ === Star.prototype); //true

        // 方法的查找规则:首先看ldh对象身上是否有sing方法,如果有就执行对象上的sing
        //如果没有sing这个方法,因为有__proto__的存在,就去构造函数原型对象prototype身上去查找sing这个方法

当给一个实例对象设置属性值时,会在实例对象中找有没有这个属性,如果找到,就直接把值赋给这个属性;如果没有的话,不会再去原型对象中找该属性,因为javascript语言是一种动态语言,这时会直接给这个实例对象添加一个新的属性,即使原型对象中有这个属性,也不会改变原型对象中的这个值。

当实例对象中和原型对象中有一个同名的属性和方法时,此时只能访问到实例对象中的属性或方法(,如果一定要访问,可以delete掉实例中的属性或方法,或都直接加上__proto__属性访问。

同样上述方法种的原型链表示如下图
在这里插入图片描述

六种继承方式

js里面的六种继承方式分别为 原型练继承、构造函数继承,实例继承,拷贝继承,组合继承,寄生组合继承
1、原型链继承
子类的实例继承自身实例属性 也继承父类里面的构造函数和方法 父类的原型属性和方法
子类的实例可以通过proto__访问到 Child.prototype 也就是Person的实例,这样就可以访问到父类的私有方法,然后再通过__proto指向父类的prototype就可以获得到父类原型上的方法。
缺点
不能继承子类的原型属性和方法
只能进行单继承,不能多继承
继承之后 原型对象上的属性全是共享
子类不能直接向父类传递参数
原型链继承实例

Animal.prototype = {
        constructor: Animal,
        sleep: function () {
            console.log(this);
        },
        height: 200
    }
    var a = new Animal();
    console.log(a.sleep());

    function fun1(){

    }
    fun1.prototype=new Child();
    var sss=new fun1();
    console.log(sss);
        console.log(child.__proto__);//  Person
    console.log(child.__proto__.__proto__); //Person 的原型对象
    console.log(child.__proto__.__proto__.__proto__); //Object
    console.log(child.__proto__.__proto__.__proto__.__proto__);

2、构造继承
通过使用call apply方法来实现继承
用.call()和.apply()将父类构造函数引入子类函数
构造函数的优点:1、可以实现多继承
2、可以向父类传递参数
缺点:1、只能继承父类的实例属性和方法,不能继承原型属性和方法
2、子类的实例是本身而不是父类

 构造函数继承
        核心使用call apply来实现继承

        function Star(n) {
            this.name = n
            this.sleep = function() {
                return "睡觉";
            }
        }
        Star.prototype.sing = "唱歌";

        function Type() {
            this.Type = arguments[0];
        }

        function Person(n, s, t) {
            this.sex = s;
            this.eat = function() {
                    return "吃饭";
                }
                //构造继承
            Star.call(this, n);
            Type.apply(this, [t])
        }
        Person.prototype = {
            constructor: Person,
            sleep: function() {

            }
        }
        var person = new Person("刘德华", "男", "歌手");
        console.log(person);
        console.log(person instanceof Person); //true
        console.log(person instanceof Star);  //false  子类的实例对象是本身而不是父类

3、实例继承
在子类内部直接构造父类的实例 直接new父类
优点:不限制调用方式 可以向父类传递参数
缺点:不能实现多继承
不能拿到子类构造函数属性和方法
子类的实例不是本身而是父类

   //js 里面的实例继承

        function Person(name, sex) {
            this.name = name;
            this.sex = sex;
            this.sleep = function() {
                return "睡觉"
            }
        }

        function Child(name, sex) {
            this.sex = sex;
            this.eat = function() { //那不到子类的属性和方法

            }
            return new Person(name, sex);
        }
        var child = new Child("刘德华", "男");
        console.log(child);

        //子类的实例对象
        console.log(child instanceof Child); //false
        console.log(child instanceof Person); //true  子类的实例对象是父类

4、拷贝继承
将父类里面的方法属性拷贝给子类
优点:
支持多继承 子类的对象实例是本身而不是父类
可以向父类传递参数
缺点:在继承的事或 不断new 占内存

 //  拷贝继承
        function Star(n) {
            this.name = n;
            this.sleep = function() {
                return "睡觉"
            }
        }

        function Type(t) {
            this.type = t;
        }

        function Person(n, s, t) {
            this.sex = s;
            this.eat = function() {
                    return "吃饭";
                }
                //拷贝父类里面的属性和方法  拷贝给原型对象prototype
                //先实例化父类对象
            var star = new Star(n);
            for (var key in star) {
                Person.prototype[key] = star[key];
            }
            var type = new Type(t);
            for (var key in type) {
                Person.prototype[key] = type[key];
            }
        }
        var ldh = new Person("刘德华", "男", "歌手");
        console.log(ldh);
        //子类对象的实例是本身 不是父类
        console.log(ldh instanceof Person); //true
        console.log(ldh instanceof Type); // false
        console.log(ldh instanceof Star); // false


5、组合继承
1、组合继承就是 原型链继承+构造继承
2、子类的实例即是本身也是父类
3、可以实现多继承
4、可以像父类传递参数
5、没有实现原型对象属性的共享
缺点:调用了两次父类的构造函数

     //组合继承
        function Father(n) {
            this.name = n;
            this.eat = function() {
                return this.name + "吃饭"
            }
        }
        Father.prototype = {
            constructor: Father,
            color: null
        }

        function Child(a, s, n) {

            this.age = a;
            this.sex = s;
            this.sleep = function() {
                return "睡觉";

            }
            Father.call(this, n); // 构造继承  只能获取到父类的属性和方法 拿不到原型属性和人方法
        }

        Child.prototype = new Father("huahua");
        var child = new Child(12, "男", "小明");
        console.log(child);
        console.log(child instanceof Child); // true
        console.log(child instanceof Father); // true  子类的实例对象是父类也是本身

6、寄生组合继承
 寄生:在函数内返回对象然后调用
 组合:1、函数的原型等于另一个实例。2、在函数中用apply或者call引入另一个构造函数,可传参 
 原理:将父类的原型对象给一个空对象的prototype 再把空对象和子类的原型对象关联


        function Animal() {
            this.name = null;
            this.sleep = function() {
                return this.name + "睡觉";
            }
        }

        Animal.prototype = {
            constructor: Animal,
            color: null
        }

        function Dog() {
            this.age = null;
            this.eat = function() {
                return this.name + "吃饭";
            }
            Animal.call(this);
        }
        //开始寄生
        (function() {
            var fn = function() {

            }
            fn.prototype = Animal.prototype;
            Dog.prototype = new fn;
        })()
        var dog = new Dog();
        console.log(dog);

        console.log(child instanceof Child); //true
        console.log(child instanceof Person); //true

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值