zoukankan      html  css  js  c++  java
  • JavaScript高级-----4.继承

    2. 继承

    2.1 call()

    • 可以调用某个函数
    • 可以修改函数运行时的this指向(注意是修改此次运行时的this指向,而不是永久的this指向)

    <script>
        // call 方法
        function fn(x, y) {
            console.log(this); //修改之前this指向的是window,修改之后this指向的是o这个对象
            console.log(x + y); //3
        }
        var o = {
            name: 'andy'
        };
        // fn();传统的函数调用方法
        // 1. call() 可以调用函数
        fn.call(); //Window {parent: Window, opener: null, top: Window, length: 0, frames: Window, …}
    
        // 2. call() 可以改变这个函数的this指向 此时这个函数的this 就指向了o这个对象
        fn.call(o, 1, 2); //{name: "andy"}
    </script>
    

    2.2 利用构造函数继承父类的属性

    ES6之前是利用构造函数继承父类的属性;利用原型对象继承父类的方法。
    利用构造函数继承父类的属性的核心方法是:通过call把父类型的this指向子类型的this,这样就可以实现子类型继承父类型的属性。

    <script>
        //借用父构造函数继承属性
        //1. 父构造函数
        function Father(uname,age){
            //这里的this原本指向父构造函数的实例对象
            this.uname = uname;
            this.age = age;
        }
    
        //2. 子构造函数
        function Son(uname, age){
            //这里的this指向子构造函数的对象实例
        }
    </script>
    

    现在上述两个构造函数没有任何关系,那么子构造函数如何才可以使用父构造函数的两个属性呢?思路:将父构造函数中的this指向改成子构造函数的实例对象。

    <script>
        // 借用父构造函数继承属性
        // 1. 父构造函数
        function Father(uname, age) {
            // this 指向父构造函数的对象实例father
            console.log(this);
            this.uname = uname;
            this.age = age;
        }
    
    
        // 2 .子构造函数 
        function Son(uname, age, score) {
            // this 指向子构造函数的对象实例
            Father.call(this, uname, age); //在调用父类构造方法的同时,将父类的this指向改为son
            this.score = score; //这是子构造函数独有的属性
        }
        var son = new Son('刘德华', 18, 100); //Son {uname: "刘德华", age: 18, score: 100}
        console.log(son); //Son {uname: "刘德华", age: 18, score: 100}
    
        var farther = new Father('张学友', 20); //父构造函数的this指向还是指向父构造函数的实例对象 Father {uname: "张学友", age: 20}
    </script>
    

    在子构造函数中写上Father.call(this, uname, age);这行代码就相当于将父构造函数的代码

    console.log(this);
    this.uname = uname;
    this.age = age;
    

    搬移到子构造函数中。子构造函数就相当于变成了

     // 2 .子构造函数 
        function Son(uname, age, score) {
            // this 指向子构造函数的对象实例
            console.log(this);
            this.uname = uname;
            this.age = age;
            this.score = score; //这是子构造函数独有的属性
        }
    

    2.3 借用原型对象继承父类型方法

    之前提到:共有的属性写在构造函数里面,共有的方法写在原型对象里
    (1)在父亲的原型对象中添加一个公共方法money()

    <script>
        // 借用父构造函数继承属性
        // 1. 父构造函数
        function Father(uname, age) {
            this.uname = uname;
            this.age = age;
        }
        //父构造函数的方法
        Father.prototype.money = function() {
            console.log(1000000);
        }
    
    
        // 2 .子构造函数 
        function Son(uname, age, score) {
            Father.call(this, uname, age);
            this.score = score;
        }
    
        var son = new Son('刘德华', 18, 100);
        console.log(son);
    </script>
    

    通过打印儿子可以看出,儿子没有继承父类的money(),儿子只是调用了父亲的构造函数,没有调用父亲的原型对象,所以儿子找不到父亲的money()

    (2)若将父构造函数的原型对象赋值给子构造函数的原型对象,如下:

    <script>
        // 借用父构造函数继承属性
        // 1. 父构造函数
        function Father(uname, age) {
            this.uname = uname;
            this.age = age;
        }
        //父构造函数的方法
        Father.prototype.money = function() {
            console.log(1000000);
        }
    
    
        // 2 .子构造函数 
        function Son(uname, age, score) {
            Father.call(this, uname, age);
            this.score = score;
        }
    
        //若将父构造函数的原型对象赋值给子构造函数的原型对象,如下
        Son.prototype = Father.prototype;
    
        var son = new Son('刘德华', 18, 100);
        console.log(son);
    </script>
    

    打印儿子,可以发现在儿子的对象原型的指向中(指向Son构造函数的对象原型)果然出现了money方法

    (3)再追加子构造函数专门的方法

    <script>
        // 借用父构造函数继承属性
        // 1. 父构造函数
        function Father(uname, age) {
            this.uname = uname;
            this.age = age;
        }
        //父构造函数的方法
        Father.prototype.money = function() {
            console.log(1000000);
        }
    
    
        // 2 .子构造函数 
        function Son(uname, age, score) {
            Father.call(this, uname, age);
            this.score = score;
        }
    
        //若将父构造函数的原型对象赋值给子构造函数的原型对象,如下
        Son.prototype = Father.prototype;
        //子构造函数专门的方法
        Son.prototype.exam = function() {
            console.log("考试");
        }
    
        var son = new Son('刘德华', 18, 100);
        console.log(son);
        //此时再打印一下父构造函数的原型对象
        console.log(Father.prototype);
    </script>
    

    此时出现问题:子构造函数的原型对象有从父构造函数中继承过来的money()也有自己独有的exam(),但是父构造函数的原型对象中也有子构造函数原型对象独有的方法exam()

    出错原因:Son.prototype = Father.prototype;相当于将父原型对象的地址给子原型对象,即让子原型对象指向父原型对象。此时若修改子原型对象,那么父原型对象回一起被修改。那么正确的继承方法是什么呢?

    <script>
        // 借用父构造函数继承属性
        // 1. 父构造函数
        function Father(uname, age) {
            // this 指向父构造函数的对象实例father
    
            this.uname = uname;
            this.age = age;
        }
        //父构造函数的方法
        Father.prototype.money = function() {
            console.log(1000000);
        }
    
    
        // 2 .子构造函数 
        function Son(uname, age, score) {
            // this 指向子构造函数的对象实例
            Father.call(this, uname, age); //在调用父类构造方法的同时,将父类的this指向改为son
            this.score = score; //这是子构造函数独有的属性
        }
        
        //正确的继承方法
        Son.prototype = new Father(); 
     
        //子构造函数专门的方法
        Son.prototype.exam = function() {
            console.log("考试");
        }
    
        var son = new Son('刘德华', 18, 100);
        console.log(son); 
        console.log(Father.prototype);
    </script>
    

    说明:Son.prototype = new Father();

    • 父构造函数创建了一个实例对象,同时将其地址赋值给Son的原型对象,即让Son的原型对象指向这个Father的实例对象
    • 而Father的实例对象可以通过自己的对象原型__proto__访问Father的原型对象prototype(链式查找)
    • 而Father的原型对象prototype中存放着money这个方法


    上述代码console.log(son);的执行结果

    console.log(Father.prototype);打印结果如下,父亲的原型对象中没有多添加子类的exam()

    但是打印console.log(Son.prototype.constructor);的时候,发现Son.prototype中的constructor指回的是父亲的构造函数

    原因:Son.prototype = new Father();等同于Son.prototype={}说明Son.prototype中的方法完全被覆盖了,Son就没有自己原先的constructor,修改办法:Son.prototype.constructor = Son;如下

    <script>
        // 借用父构造函数继承属性
        // 1. 父构造函数
        function Father(uname, age) {
            // this 指向父构造函数的对象实例father
    
            this.uname = uname;
            this.age = age;
        }
        //父构造函数的方法
        Father.prototype.money = function() {
            console.log(1000000);
        }
    
    
        // 2 .子构造函数 
        function Son(uname, age, score) {
            // this 指向子构造函数的对象实例
            Father.call(this, uname, age); //在调用父类构造方法的同时,将父类的this指向改为son
            this.score = score; //这是子构造函数独有的属性
        }
    
        Son.prototype = new Father(); 
    
        //修改办法:如果利用对象的形式修改了原型对象,别忘了用constructor指回原来的构造函数
        Son.prototype.constructor = Son;
    
        //子构造函数专门的方法
        Son.prototype.exam = function() {
            console.log("考试");
        }
    
        var son = new Son('刘德华', 18, 100);
        console.log(son); //Son {uname: "刘德华", age: 18, score: 100}
        console.log(Father.prototype);
        console.log(Son.prototype.constructor); //!!!指向了父构造函数
    </script>
    
  • 相关阅读:
    Qt原始资源形象问题后删除
    HTML基金会2----联系,像, 第,对齐
    hibernate学习笔记(1)hibernate基本步骤
    WinHEC(Windows硬件project产业创新峰会)将2015回归
    Webx相框:RequestContext详细说明
    ActionBarActivity: cannot be resolved to a type
    Java8 Lambda表达应用 -- 单线程游戏server+异步数据库操作
    正确使用Android性能分析工具——TraceView
    用Swift完成不同View Controller之间的切换
    最简单也最难——如何获取到Android控件的高度
  • 原文地址:https://www.cnblogs.com/deer-cen/p/12384506.html
Copyright © 2011-2022 走看看