js的繼承,call()方法的運用(1)

在es6之前,是沒有extends繼承的,我們都是通過構造函數,原型對象來模擬,實現了繼承.
爲什麼這麼說呢?
這是因爲我們是利用構造函數來繼承屬性,利用原型對象來繼承方法的
.現在我們就可以通過call( ),apply( ),bind( )這三個方法也可以實現繼承.

call( );

用法

   fn.call(thisArg, arg1, arg2, ...)

thisArg : 當前調用函數this的指向對象;
arg : 傳遞的參數

call( )方法的作用

  • 可以調用函數
 function fn() {
            console.log("123");

        }
        fn.call(); //123

這裏我利用call方法也可以正常的調用函數

  • 可以修改函數裏面的this指向
    首先我先看一下函數fn裏面的this指向的是window
function fn() {
            console.log("123");
            console.log(this); //window{....}

        }
        var obj = {
            name: '小明'
        }
        fn.call(); //123
        fn.call(obj) //{name: "小明"}

這時 f n 這個函數裏面的this就指向了obj這個對象
call()裏面的第一個參數是指向的對象

如果我要傳遞參數的時候就可以這樣做

  function fn(a, b, c) {
            console.log(a + b + c);
        }
        var obj = {
            name: '小明'
        }
        fn.call(obj, 1, 2, 3) //6

直接跟普通函數一樣傳參就好了.
call( )裏面的第一個參數是不參與傳遞的,只是改變this的指向

利用構造函數來繼承屬性

這兩個構造函數裏面的this指向
Cat構造函數裏面的this指向的是它的對象實例
Dog構造函數裏面的this指向的是它的對象實例

 function Cat(name, age) {
            this.name = name;
            this.age = age;
        }

 function Dog(namem, age) {
            
        }

如果我的Dog構造函數需要使用到Cat構造函數裏面的屬性,那我就可以把Cat裏面的屬性繼承過來
這時候我可以這樣

function Cat(name, age) {
            this.name = name;
            this.age = age;
        }

        function Dog(namem, age) {
        //這裏的this指向的是Dog構造函數的實例
            Cat.call(this,name,age)
        }
        var dog = new Dog('小白', 2)
        console.log(dog); //Dog{name:"小白",age:2}

在Dog構造函數裏面通過call( )方法調用了Cat構造函數,然後把Cat構造函數的this改成了Dog構造函數的this,這樣Dog構造函數就可以使用Cat構造函數裏面的屬性了. 然後把需要的參數傳進去.
驗證一下可以看到成功了, 這樣就借用了構造函數來實現繼承屬性

核心原理:在子構造函數裏面調用父構造函數,同時把父構造函數的this指向子構造函數的this,

利用原型對象來繼承方法

   function Cat(name, age) {
            this.name = name;
            this.age = age;
        }
        Cat.prototype.eat = function() {
            console.log('我會吃飯');
        }

        function Dog(name, age) {
            Cat.call(this, name, age)
        }
        var dog = new Dog('小白', 2)
        console.log(dog);

現在我在Cat原型對象上添加了一個eat的方法,這時我Dog構造函數需要繼承我這個方法,那我應該怎麼做呢???
那我能不能這樣呢,把我Dog構造函數的原型對象指向Cat的原型對象呢? 那我試試

 function Cat(name, age) {
            this.name = name;
            this.age = age;
        }
 Cat.prototype.eat = function() {
            console.log('我會吃飯');
        }
 function Dog(name, age) {
         	Cat.call(this, name, age);
        }
        //這一步
        Dog.prototype = Cat.prototype;
        var dog = new Dog('小白', 2)
        console.log(dog);
        

寫完後我驗證一下,可以看到是可以拿到這個方法的
在這裏插入圖片描述
好了,那就實現了方法的繼承,是不是很美好.
問題來了
那如果Dog裏面有自己獨享的方法呢?我再來看看
我在Dog原型對象上面寫了一個Dog獨享的方法

 Dog.prototype.eatBone = function() {
            console.log('我會啃骨頭');
        }

毫無疑問,Dog的實例對象可以訪問到這個方法,那我Cat構造函數能不能訪問到這個方法呢.我打印一下,看看有木有問題哇
那我去Cat構造函數的原型對象上看看哈…

console.log(Cat.prototype);

咦…看到了吧,本來我Dog構造函數裏面的eatBone是自己獨享的
可是我打印出來的時候,這個方法也被Cat構造函數共享了.
這就是大問題了,也就是說,我不想給你的你卻也能得到,是不是很傷心呢?
接下來就解決這個問題;
在這裏插入圖片描述
原因就是我那一步操作

 Dog.prototype = Cat.prototype;

也就相當於我把Dog構造函數的原型對象指向了Cat構造函數的原型對象雖然可以把Cat裏面原型對象上的方法繼承過來,但是反過來說Dog裏面原型對象上的一些自己的方法也被傳過去了;

所以我們千萬不能這樣做,因爲如果修改了子原型對象的話,父原型對象也會跟着變
那我們該怎麼解決這個問題???
我們可以這樣

Dog.prototype = new Cat();

然後我再驗證

console.log(Cat.prototype) 

看成功了,給Dog原型對象上添加方法,對Cat原型對象沒有任何影響
在這裏插入圖片描述
我們來看看原理這一步操作的原理

Dog.prototype = new Cat();

我 new Cat( ),就相當於創建了一個實例對象(實例化一個對象).
然後把實例化的對象賦值給了Dog.prototype,就相當於把Dog的原型對象指向了剛剛創建的實例對象

那我在問你,我Cat的實例對象能訪問到我Cat的原型對象嗎?
那肯定是可以的對不對;說到這相信大家都明白怎麼回事了吧
我畫個圖給你們瞧瞧,
在這裏插入圖片描述
這樣大家都明白了吧, 再捋一捋
我 new Cat( ),就相當於創建了一個實例對象(實例化一個對象).
然後把實例化的對象賦值給了Dog.prototype,就相當於把Dog的原型對象指向了剛剛創建的實例對象
又因爲實例對象裏面有__proto__原型,通過這個原型我們就可以訪問原型對象.而這個原型對象上有eat( )這個需要被繼承的方法.就這樣,我Dog的原型對象就可以間接的訪問到Cat的原型對象,就可以拿到那裏面的方法.

我Dog裏面私有的方法還是自己的,就算改變了自己的原型對象,對Cat的原型對象也沒有任何影響;
這樣做法還是有一個問題的,不知道大家有沒有發現

Dog.prototype = new Cat();

我這樣是不是一個賦值操作呀,這樣寫過後,我Dog.prototype裏面的constructor屬性呢???(上一篇文章說道)
是吧,所以我們到最後還是要把它加上

 //重新指回Dog構造函數
        Dog.prototype.constructor = Dog;

最後完美成功實現繼承了

function Cat(name, age) {
            this.name = name;
            this.age = age;
        }
        Cat.prototype.eat = function() {
            console.log('我會吃飯');
        }

        function Dog(name, age) {
            Cat.call(this, name, age)
        }
        Dog.prototype = new Cat();
        //重新指回Dog
        Dog.prototype.constructor = Dog;
        // Dog.prototype = Cat.prototype; //不能這樣做
        Dog.prototype.eatBone = function() {
            console.log('我會啃骨頭');

        }
        var dog = new Dog('小白', 2)
        console.log(dog);
        console.log(Cat.prototype);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章