原型对象(下)

一、原型链

是一种关系,实例对象和原型对象之间的关系,关系是通过原型(__proto__)来联系的

二、原型指向改变:

  • 实例对象的原型(__proto__)指向的是该对象所在的构造函数的原型对象,
  • 构造函数的原型对象(prototype)的指向如果改变了,实例对象的原型(__proto__)指向会跟着改变
   <script>
        //人的构造函数
        function Person(age){
            this.age=age;
        }
        //人的原型方法
        Person.prototype.show=function(){
            console.log("");
        }
        //学生的构造函数
        function Student(age){
         
        }
        //学生的原型方法
        Student.prototype.show=function(){
            console.log("学生");
        }
        //学生的原型方法改变,指向了人的一个实例对象
        Student.prototype=new Person(10);
        var stu=new Student();
        stu.show();//
    </script>

三、原型最终指向

  • 对象都有一个__proto__原型,__proto__指向某个构造函数的原型prototype
  • 实例对象(__proto__)指向的是该构造函数的(prototype)
  • 该构造函数的的prototype也是一个对象,__proto__原型指向的是object的原型(prototype)
  • object的原型prototype也是一个对象,__proto__原型指向的是null
   <script>
        //人的构造函数
        function Person(age){
            this.age=age;
        }
        //人的原型方法
        Person.prototype.show=function(){
            console.log("");
        }
        var per=new Person( );
        console.log(per.__proto__==Person.prototype);//true
        console.log(Person.prototype.__proto__==Object.prototype);//true
        console.log(Object.prototype.__proto__);//null
    </script>

四、原型指向如果改变了,那么应该在原型指向改变后添加原型方法

 <script>
        //人的构造函数
        function Person(age){
            this.age=age;
        }
        //人的原型方法
        Person.prototype.sayHi=function(){
            console.log("你好");
        }
        //改变指向----一个新对象
        Person.prototype={
            eat:function(){
                console.log("吃饭")
            }
        }
        var per=new Person(10);//报错
        per.sayHi();
    </script>
   <script>
        //人的构造函数
        function Person(age){
            this.age=age;
        }
        //改变指向----一个新对象
        Person.prototype={
            eat:function(){
                console.log("吃饭")
            }
        }
        //人的原型方法
        Person.prototype.sayHi=function(){
            console.log("你好");
        }
        var per=new Person(10);//你好
        per.sayHi();
    </script>

五、举例:一个div的原型链

   <div id="dv"></div>
    <script>
        var divObj=document.getElementById("dv");
        console.log(divObj.__proto__);//HTMLDivElement
        //divObj.__proto__-------HTMLDivElement中的prototype
        //HTMLDivElement.prototype中的__proto__------Element中的prototype
        //Element.prototype中的__proto__------Node中的prototype
        //Node.prototype中的__proto__------EventTarget中的prototype
        //EventTarget.prototype中的__proto__------Object中的prototype
        //Object.prototype中没有__proto__------null
    </script>

六、总结原型

  • 面向对象的特性:封装,继承,多态
  1. 封装就是包装,一个值存储在一个变量中,或者一堆代码放在一个函数中,或者一系列属性放在一个对象中,或者多种类似的对象放在一个js文件中
  2. 继承是一种关系,父类级别与类级别的关系,js中没有类,但是可以通过构造函数模拟类,然后通过原型来继承
  • 原型的作用之一:数据共享,目的节省内存空间
  • 原型的作用之二:为了实现继承,目的节省内存空间
   <script>
        //Person的构造函数
        function Person(name,age,sex){
            this.name=name;
            this.age=age;
            this.sex=sex;
        }
        //Person添加原型方法
        Person.prototype.eat=function(){
            console.log("吃饭");
        };
        Person.prototype.sleep=function(){
            console.log("睡觉");
        };
        Person.prototype.play=function(){
            console.log("玩球");
        };
        //Student的构造函数
        function Student(score){
            this.score=score;
        }
        //改变学生的原型的指向=========>继承人的原型方法
        //通过原型的继承,可以减少相同代码的书写,不会造成代码冗余
        Student.prototype=new Person("小明",10,"");
        //Student添加原型方法(在指向改变之后)
        Student.prototype.study=function(){
            console.log("学习");
        };
        var stu=new Student(100);
        console.log(stu.score);//100
        console.log(stu.name);//小明
        console.log(stu.age);//10
        console.log(stu.sex);//
        stu.study();//学习
        stu.eat();//吃饭
        stu.sleep();//睡觉
        stu.play();//玩球
    </script>

七、借用构造函数继承

  • 为了数据共享,改变原型指向,做到了继承(通过改变原型指向的继承)
  • 缺陷:因为改变原型指向的同时实现的继承,直接初始化了属性,继承过来的值都是一样的
  • 解决办法就是使用借用构造函数的方法(构造函数.call(对象,属性1,属性2,......))
   <script>
        function Person(name,age,weight,sex){
            this.name=name;
            this.age=age;
            this.weight=weight;
            this.sex=sex;
            this.show=function(){
                console.log("");
            };
        }
        Person.prototype.sayHi=function(){
            console.log("你好");
        };
        function Student(name,age,weight,sex,score){
            Person.call(this,name,age,weight,sex);
            this.score=score;
        }
        var stu=new Student("小明",18,"50kg","",100);
        console.log(stu.name);//小明
        console.log(stu.age);//18
        console.log(stu.weight);//50kg
        console.log(stu.sex);//
        console.log(stu.score);//100
        stu.show();//人(实例对象的方法可以继承)
        stu.sayHi();//报错(原型添加的方法不能继承)
    </script>

八、组合继承

  • 借用构造函数的方法无法继承原型添加的方法
  • 解决办法是使用组合继承:原型继承+借用构造函数继承
   <script>
        //Person的构造函数
        function Person(name,age,weight,sex){
            this.name=name;
            this.age=age;
            this.weight=weight;
            this.sex=sex;
            this.show=function(){
                console.log("");
            };
        }
        //Person原型添加的方法
        Person.prototype.sayHi=function(){
            console.log("你好");
        };
        //Student的构造函数
        function Student(name,age,weight,sex,score){
            //借用构造函数继承
            Person.call(this,name,age,weight,sex);
            this.score=score;
        }
        //原型指向改变继承原型添加的方法
        Student.prototype=new Person();
        var stu=new Student("小明",18,"50kg","",100);
        console.log(stu.name);//小明
        console.log(stu.age);//18
        console.log(stu.weight);//50kg
        console.log(stu.sex);//
        console.log(stu.score);//100
        stu.show();//
        stu.sayHi();//你好
    </script>

九、拷贝继承:

把一个对象中的属性或者方法,通过遍历的方法,直接复制到另外一个对象中

    <script>
        function Person(name){
            this.name=name;
        }
        Person.prototype.age=10;
        Person.prototype.sex="";
        Person.prototype.weight="60kg";
        Person.prototype.sayHi=function(){
            console.log("你好");
        };
        var obj2={};
        //Person的构造函数中有原型对象prototype,prototype就是一个对像,那么age,sex,weight,sayHi都是该对象的属性和方法
        for(var key in Person.prototype){
            obj2[key]=Person.prototype[key];
        }
        console.log(obj2.age);//10
        console.log(obj2.sex);//
        console.log(obj2.weight);//60kg
        obj2.sayHi();//你好
    </script>

十、逆推继承看原型

    <script>
        function F1(age){
            this.age=age;
        }
        function F2(age){
            this.age=age;
        }
        F2.prototype=new F1(10);
        function F3(age){
            this.age=age;
        }
        F3.prototype=new F2(20)
        var f3=new F3(30);
        console.log(f3.age);//30
    </script>

原文地址:https://www.cnblogs.com/EricZLin/p/9062127.html