首页 > 其他分享 >js继承

js继承

时间:2023-12-14 15:01:02浏览次数:25  
标签:name 继承 age js Person Student 父类 构造函数

继承 extend

构造函数的应用

当多个构造函数需要使用一些共同的方法或者属性的时候,我们需要把这些共同的东西拿出来,单独书写一个构造函数,让其他的构造函数去继承自这个公共的构造函数

概念:让B构造函数的实例能够使用A构造函数的属性和方法,我们管B构造函数叫做A构造函数的子类,A构造函数叫做B构造函数的父类

目的:让B构造函数能够使用A构造函数的属性和方法. (子类的实例使用父类的属性和方法)

//-------------------原型继承
//---------- 准备一个父类  
function Person(name,age){
            //
            this.name=name;
            this.age=age;
        }
        Person.prototype.sayHi=function(){
            console.log('hello world')
        }
        /* 
        person的实例={
            name:'jack',
            age:18,
            __proto__:{//Person.prototype
                constructor:Person,            
                sayHi:function(){
                  console.log('hello world')
                },
                __proto__:Object.prototype

            }
        }
        
        原型继承
            利用改变 原型链的方式来达到继承的效果
            直接把父类的实例当做子类的 prototype

        构造函数的原型 对象
            我们把原型赋值为一个新的对象
            new Person的时候,得到的也是一个新的对象
            核心代码: 子类.prototype = new 父类

        原型继承的优缺点:
        优点:构造函数体内和原型上的都可以继承
        缺点:
            1: 一个构造函数的内容,在两个位置传递参数
            2: 继承来的属性不再子类实例的身上,看起来很别扭
            
        
        */
				//---子类
        function Student(gender){
            this.gender=gender;

        }
        //const p=new Person('jack',18);
        //直接把父类的实例当做子类的原型对象
				//Student.prototype=p;

        //直接把父类的实例当做子类的原型对象
				Student.prototype=new Person('jack',18);

        const s=new Student('男');
        console.log(s);
        /* 
            Student
                gender: "男"
                [[Prototype]]: Person       //即是Student.prototype 也是 Person的实例
                    age: 18
                    name: "jack"
                    [[Prototype]]: Object  //Person的prototype
                        sayHi: ƒ ()
                        constructor: ƒ Person(name,age)
                        [[Prototype]]: Object
                        ......
        */

        s.sayHi(); //student的实例用了Person的方法 
//---------------------借用继承
     /* 
        借用构造函数继承 (借用继承/call 继承)
        通过改变父类的构造函数的 this指向来达到继承的效果
        核心代码:在子类的构造函数体内,父类.call(子类的实例)

        构造函数的执行
            1 是一个普通函数,可以当做函数直接调用
            2 当做普通函数执行的时候,this指向谁,就向谁身上添加内容
            3 call 方法可以改变函数的this指向
    
    */
        //父类
       function Person(name,age){
            
            this.name=name;
            this.age=age;
        }
        Person.prototype.sayHi=function(){
            console.log('hello world')
        }
        //function Student(gender,name,age){
        function Student(gender){
            this.gender=gender;

            /* 
                将Person函数当做普通函数调用
                使用call方法改变了一下Person函数内部的this指向
                改变成指向谁就会向谁身上添加一个name 一个age属性
                当我们new Student的时候,Strdent内部这个位置的this指向Studend的实例对象
                我们使用call方法改变了Person函数内的指向,指向了 Student的实例 this === s


                借用继承的优缺点:
                优点:
                    1:继承来的属性是在自己身上
                    2:我们一个实例化的过程在一个位置传参
                缺点:
                    只能继承父类构造函数体内的内容
                    父类原型上的内容不能继承

            
            */
            Person.call(this,'rose',16);//可以在上面传参 
            // Person.call(this,name,age);//可以在上面传参 
            //这个函数执行完毕以后,会像Student的实例身上添加一个name 一个age属性

        }
  
        //书写属于 student自己方法
        Student.prototype.stduy=function(){
            console.log('学术的天职就是好好学习');
        }
        var s=new Student('男');
        // var s=new Student('男','rose',16);
      console.log(s);//
      /* 
      Student {gender: '男', name: 'rose', age: 16}
        age: 16
        gender: "男"
        name: "rose"
        [[Prototype]]: Object
            stduy: ƒ ()
            constructor: ƒ Student(gender)
            [[Prototype]]: Object
      
      
      */
//------------组合继承
/* 
        -----------组合继承
        把原型继承 和 借用构造函数继承 合并在一起使用
        组合继承的优缺点:
        优点:
            1: 父类构造函数体内 和原型上的内容能继承
            2: 继承下来的属性放在自己身上
            3: 在一个位置传递所有参数
        缺点:
            1:当你的子类添加方法的时候,实际是添加在了父类的实例上(但是这一点不影响我们使用)
            
            2018年前大部分人继承都是使用这种方式

    
    */

    //父类
    function Person(name,age){
            
            this.name=name;
            this.age=age;
        }
    Person.prototype.sayHi=function(){
        console.log('hello world')
    }
    //子类
    function Student(gender,name,age){
            this.gender=gender;
            //借用继承 ,目的:把属性继承在自己的身上
            Person.call(this,name,age)
    }

    //原型继承,目的:继承父类原型上的方法
    Student.prototype=new Person();//这个位置的参数可传可不传 因为自己身上有就不会向原型上找

    //书写属于 student自己方法
    Student.prototype.stduy=function(){
        console.log('学术的天职就是好好学习');
    }
    //使用student 创建实例
    var s=new Student('男','sun',1200)
    console.log(s);
    /* 
    Student {gender: '男', name: 'sun', age: 1200}
    age: 1200
    gender: "男"
    name: "sun"
        [[Prototype]]: Person
            age: undefined
            name: undefined
            stduy: ƒ ()
            arguments: null
            caller: null
            length: 0
            name: ""
                prototype: {constructor: ƒ}
                    [[FunctionLocation]]: 继承.html:155
                    [[Prototype]]: ƒ ()
                    [[Scopes]]: Scopes[1]
                    [[Prototype]]: Object
                    sayHi: ƒ ()
                    constructor: ƒ Person(name,age)
                    [[Prototype]]: Object
    
    
    
    */

    // -----------------------------------拷贝继承(for in继承)
/* 
    
     拷贝继承(for in继承)
     利用for in循环的特点,来继承所有的内容
     先实例化一个父类的实例
     使用for in循环来遍历这个实例对象,因为for in循环可以遍历对象自己身上的属性还会遍历———proto———上的属性
     直接把父类实例身上的所有内容直接复制到子类的prototype



    
    */
   //父类
    function Person(name,age){
            
            this.name=name;
            this.age=age;
        }
    Person.prototype.sayHi=function(){
            console.log('hello world')
    }

    // var p=new Person('jack',18);
    // for(var key in p){
    //     console.log(key);//name age sayHi
    // }

    //子类
    function Student(gender,name,age){
        this.gender=gender;
        //for in 继承
        var p=new Person(name,age);
        for(var key in p){
            // console.log(key);//name age sayHi
            //将p实例的属性及原型上的方法 添加到Student的原型上
            Student.prototype[key]=p[key];
        }
    }

    Student.prototype.stduy=function(){
        console.log('学术的天职就是好好学习');
    }
    const s=new Student('男','sun',199)
    console.log(s);

    /* 
    
    Student {gender: '男'}
        gender: "男"
        [[Prototype]]: Object
            age: 199
            name: "sun"
            sayHi: ƒ ()
            stduy: ƒ ()
            constructor: ƒ Student(gender,name,age)
            [[Prototype]]: Object
    */
    /* 

        拷贝继承的优缺点:
        优点:
         1:父类的构造函数体内的和原型上的属性和方法都可以继承
         2:在同一个位置传参
         3:constructor 能正常配套
         4:添加自己的方法的时候,确实是在自己的原型身上
         总体来说这个继承还好很不错的

        缺点:
         1:for in循环需要一直遍历到Object.prototype ,很消耗性能
         2:不能继承不可枚举的属性
         3:继承来的属性不在自己的身上

    */
	//----------寄生继承  
    /* 
        构造函数不要写return
           return 一个基本数据类型 ,写了白写
           return 一个复杂数据类型,构造函数没有意义
    
        寄生继承1
        寄生继承实际上是一种伪继承 
        (最敷衍的一个继承但是确实达到了继承的目的:在子类中使用父类的属性)
        
        核心代码:
            const instance=new Person(name,age)
            return instance
    
    */

    //父类
    function Person(name,age){
        
        this.name=name;
        this.age=age;
    }
    Person.prototype.sayHi=function(){
        console.log('hello world')
    }
    //子类
    function Student(name,age){
            this.gender='男';
         //寄生继承1----------------------------
         const a=new Person(name,age);
        
         //--3  将父类实例的原型改为子类的原型
         a.__proto__=Student.prototype;

         //在子类里面直接retuen 父类的实例
         return a;
    }

    //---2  书写属于 student自己方法  在修改原型前设置不上去
    Student.prototype.stduy=function(){
        console.log('学术的天职就是好好学习');
    }
    var s=new Student('rose22',19);
    console.log('---',s);//s确实是new Student的实例,但是真实的内容是Person的实例
    /* 
        Person {name: 'rose', age: 19}
            age: 19
            name: "rose"
            [[Prototype]]: Object
                sayHi: ƒ ()
                constructor: ƒ Person(name,age)
                [[Prototype]]: Object

        //---将父类实例的原型改为子类的原型后的打印

        Person {name: 'rose22', age: 19}
            age: 19
            name: "rose22"
            [[Prototype]]: Object
            stduy: ƒ ()
            constructor: ƒ Student(name,age)
            [[Prototype]]: Object

    */

    /* 
    
     ----------------寄生继承2-------------------
        出现了第二种寄生继承
        不直接寄生实例,寄生原型

        
    
    */
    function Student(gender){
        this.gender=gender;

    }
    //寄生实例
    Student.prototype=Person.prototype;
    //想要的在自己的原型上添加一些方法的时候,父类的原型上也有了这个方法
    Student.prototype.stduy=function(){
        console.log('好好学习');
    }
    const s2=new Student('男')
    console.log(s2);
    
    const p1=new Person('sun',100)
    console.log(p1);


    /* 
    
    寄生继承的优缺点:
        优点:号称完美继承
            1 原型和构造函数体内的都可以继承
            2 寄生原型的话,自己的属性和方法依旧可以添加和使用
        缺点:
            1: 寄生实例的时候,没有自己的任何内容
            2:寄生原型的时候,一旦修改原型,父类的实例也会有这些方法
    
    */
/* 

    //----------------------------------寄生组合继承(完美继承)
    合并了 寄生继承 + 原型继承 + 第三方的构造函数 + 借用继承


*/

    //父类
    function Person(name,age){             
                this.name=name;
                this.age=age;
    }
    Person.prototype.sayHi=function(){
            console.log('hello world')
    }
    function Abc(){
    
    }


    //子类
    function Student(gender,name,age){
        this.gender=gender;
        //借用继承 :继承来父类的属性 直接将父类的属性放到自己的身上
        Person.call(this,name,age)
    }
    //如果这样写的话 子类原型直接为父类的原型,如果需要向子类的原型上添加方法时,那父类的原型上也就有了
    //这样的话调用父类时候,父类实例也就有了子类的方法,不推荐
    //Student.prototype=Person.prototype

    //使用立即执行函数的目的是为了变量私有化
    //----------核心代码
   (function(){
       //声明一个第三方的构造函数
        function Abc(){    
        }
        //让第三方的构造函数的原型为父类的原型 这样就得到父类原型上的方法
        Abc.prototype=Person.prototype;

        //子类的原型为 第三方函数的实例
        Student.prototype=new Abc();
     
   }())

    //向子类的原型上添加方法 实际是添加到了第三方函数的实例上了,这样不会污染父类的原型
    Student.prototype.stduy=function(){
        console.log('学术的天职就是好好学习');
    }
    var s=new Student('男','sun',1700)
    console.log(s);

    /* 
    
    Student {gender: '男', name: 'sun', age: 1700}
    age: 1700               //----------这样既有了父类的属性
    gender: "男"
    name: "sun"
    [[Prototype]]: Person
        stduy: ƒ ()         //-----------又可以在原型上设置自己的方法且不会污染父类
        [[Prototype]]: Object
            sayHi: ƒ ()     //-----------继承了父类原型上的方法
            constructor: ƒ Person(name,age)
            [[Prototype]]: Object

    //---这样既有了父类的属性,又可以在原型上设置自己的方法且不会污染父类,又继承了父类原型上的方法
    
    */
   

    //创建父类的实例打印,发现父类不受任何影响
    console.log('_____', new Person('zju',16));
 /* 
        ----------------------------ES6 类型继承-----------------------
        es6 把继承这个使用变成了关键字   实际上就是封装了寄生组合继承
        1:extends
            class 子类类名 extends 父类{}
        2: super()
            在 constructor里面书写一个supper()
            super(name,age) 等价于 Person.call(this,name,age)

        注意:
            1:super需要写在 constructor 里面
            2:如果你要写自己的属性,必须写在supper后面
            3:es6 的继承可以继承ES5的构造函数 也可以继承es6的类

    */
      //父类
    //---es5 构造函数
    // function Person(name,age){
        
    //     this.name=name;
    //     this.age=age;
    // }
    // Person.prototype.sayHi=function(){
    //         console.log('hello world')
    // }

    //---es6 类
    class Person{
        constructor(name,age){
            this.name=name;
            this.age=age;
        }
        sayHi(){
            console.log('hello word');
        }
    }

   console.log(new Person('小红',23));

    //------es6中创建一个类
    // class Student{
    //     constructor (gender){
    //         this.gender=gender;
    //     }
    //     stduy(){
    //         console.log('好好学习');
    //     }
    // }

    //-----es6中通过关键字实现子类继承父类
    class Student extends Person{
        constructor (gender,name,age){  
            //super() 要写在自己的属性前面
            //super(name,age)等价于 Person.call(this,name,age)
            super(name,age);
            this.gender=gender;
        }
        stduy(){
            console.log('好好学习');
        }
    }
    
    console.log('---',new Student('女','rose',18));
    /* 
        Student {name: 'rose', age: 18, gender: '女'}
            age: 18
            gender: "女"
            name: "rose"
            [[Prototype]]: Person
                constructor: class Student
                stduy: ƒ stduy()
                [[Prototype]]: Object
                    sayHi: ƒ ()
                    constructor: ƒ Person(name,age)
                    [[Prototype]]: Object

    */

类语法

在es5中,我们使用函数来充当 构造函数(类)

Es6 引入一个类的概念,就是使用一个新的关键字 class 来定义类, class 是构造函数的语法糖

注意:一个class定义的类,不能被当做普通函数调用,必须要和new关键字连用,不然就报错

​ 只能通过一个new来得到一个对象

语法:

--------------------定义一个类
class 类名{
    // 构造器 ,等价于我们的构造函数 ,定义这个类创造的对象里有哪些属性
  //一个类必须有constructor()方法,如果没有显式定义,一个空的constructor()方法会被默认添加。
    constructor(a,b){
        this.属性名1=a;
        this.属性名2=b;
    }
    // ------ 直接书写原型上的方法,不用function: 
    // ------  方法与方法之间不需要逗号 , 分隔,加了会报错
    方法名1(){
        console.log('***',this)
    }
    方法名2(){
        console.log('***',this)
    }
    方法名3(){
        console.log('***',this)
    }
}
-----------------定义一个名为Person的类
class Person{
    // 构造器 ,这个类创造的对象里有哪些属性
    constructor(a,b){
        this.name=a;
        this.age=b;
    }
    // 直接书写原型上的方法,不用function: 
    // 也不用,
    init(){
        console.log('***',this)
    }
}

//---使用Person类去创建对象
var newObj1=new Person('你好',100);   //----得到一个实例对象
newObj1.init1();                    //----调用实例对象的方法,方法中的this指向这个创建出来的实例对象


 //ES5 一样,类的所有实例共享一个原型对象。
//newObj1和newObj2都是Person的实例,它们的原型都是Person.prototype,所以__proto__属性是相等的。
newObj1.__proto__ === newObj2.__proto__

标签:name,继承,age,js,Person,Student,父类,构造函数
From: https://www.cnblogs.com/zwteast/p/17901180.html

相关文章

  • gsap基础-JS动画库
    https://blog.csdn.net/m0_61662775/article/details/131430585https://blog.csdn.net/changbb/article/details/131675810学习文档简介GSAP的全名是GreenSockAnimationPlatform一直发展到今天已经是3.x版本,这是一个适用于现代浏览器的专业Javascript动画库核心语法......
  • js excel操作
    Js操作Excel常用方法Js操作Excel常用方法1.创建一个新Excel表格    varXLObj=newActiveXObject("Excel.Application");    varxlBook=XLObj.Workbooks.Add;                         //新增工作簿    varExcelSheet=xlBook.Wo......
  • JS监听系统是否为暗黑模式
    //在App.vue文件下定义即可//useDark()和useToggle()均需要安装@vueuse/core包即可使用npminstallelement-plus--save安装Element-Plusnpminstall@vueuse/core--save安装@vueuse/coreif(window.matchMedia('(prefers-color-scheme:dar......
  • 【前端面试必读】在js中为什么0.1+0.2不等于0.3
    原因在于在JS中采用的IEEE754的双精度标准,计算机内部存储数据的编码的时候,0.1在计算机内部根本就不是精确的0.1,而是一个有舍入误差的0.1。当代码被编译或解释后,0.1已经被四舍五入成一个与之很接近的计算机内部数字,以至于计算还没开始,一个很小的舍入错误就已经产生了。这也就是0.......
  • nodejs运算中的失精问题
    nodejs运算中的失精问题问题呈现分析问题如何解决 问题呈现leta=0.1,b=0.2,c=0.3,d=0.4;console.log(a+b)//0.30000000000000004console.log(a-c)//-0.19999999999999998sonsole.log(a-d)//-0.30000000000000004分析问题JavaScript......
  • MySQL使用JSON存储数据
    1.优点1.不用为数据中的每个key值新建一个字段,可以任意的增减字段而无需修改数据表结构,甚至可以减少数据表的设计。2.可以减少数据表的查询,减少关联查询,一个查询的结果就可以代替几个查询的结果,降低数据库服务器的压力。2.缺点1、json数据仅仅只能用于展示display,如果用于条件......
  • import引入pdfjs-dist报错Top-level await is not available、No "GlobalWorkerOption
    项目环境//1.npmlsvite├─┬@vitejs/[email protected]│└──[email protected]├─┬@vitejs/[email protected]│└──[email protected]├─┬[email protected]│└──[email protected]├─┬[email protected]│└......
  • [转]cryptoJs DES_CBC_Pkcs7 转成 Java(对称加密早期协议"DES"现已不安全,仅用于老项
    原文地址:cryptoJsDES_CBC_Pkcs7转成Java-唯学而知-博客园前端DES加密:importcryptoJsfrom'crypto-js';//DES加密functionencrypt(message,key,iv){//字符串转16进制constkeyHex=cryptoJs.enc.Utf8.parse(key);constivHex=cryptoJs.enc.U......
  • Java第九课_继承
    3.面向对象的编程_继承继承publicclassPractice{publicstaticvoidmain(String[]args){/*继承/extends:子类继承父类后,子类可以获取父类中所有的非私有的成员;子类:被抽取共同成员的类,通常是多个类,StudentWorker......
  • 继承
    继承/extends:子类继承父类后,子类可以获取父类中所有的非私有的成员;子类:被抽取共同成员的类,通常是多个类,StudentWorker父类:共同成员所在的类,通常是少的一方,PersonJava中的类与类之间的继承是:单继承,支持多层继承Object类:上帝类,是所有类的父......