原型、原型對象和繼承

js中有一個話,叫萬物皆對象,因為js是基于原型的

原型

當(dāng)我們創(chuàng)建一個對象時 let obj = { age: 25 },我們可以發(fā)現(xiàn)能使用很多種函數(shù),但是我們明明沒有定義過它們,對于這種情況你是否有過疑惑?

image.png

當(dāng)我們在瀏覽器中打印 obj 時你會發(fā)現(xiàn),在 obj 上居然還有一個 proto 屬性,那么看來之前的疑問就和這個屬性有關(guān)系了。

其實每個 JS 對象都有 proto 屬性,這個屬性指向了原型。這個屬性在現(xiàn)在來說已經(jīng)不推薦直接去使用它了,這只是瀏覽器在早期為了讓我們訪問到內(nèi)部屬性 [[prototype]] 來實現(xiàn)的一個東西。

講到這里好像還是沒有弄明白什么是原型,接下來讓我們再看看 proto 里面有什么吧。

image.png

看到這里你應(yīng)該明白了,原型也是一個對象,并且這個對象中包含了很多函數(shù),所以我們可以得出一個結(jié)論:對于 obj 來說,可以通過 proto 找到一個原型對象,在該對象中定義了很多函數(shù)讓我們來使用。

在上面的圖中我們還可以發(fā)現(xiàn)一個 constructor 屬性,也就是構(gòu)造函數(shù)


image.png

打開 constructor 屬性我們又可以發(fā)現(xiàn)其中還有一個 prototype 屬性,并且這個屬性對應(yīng)的值和先前我們在 proto 中看到的一模一樣。所以我們又可以得出一個結(jié)論:原型的 constructor 屬性指向構(gòu)造函數(shù),構(gòu)造函數(shù)又通過 prototype 屬性指回原型,但是并不是所有函數(shù)都具有這個屬性,F(xiàn)unction.prototype.bind() 就沒有這個屬性。

所以每一個構(gòu)造函數(shù)都有一個原型對象(也就是Person.prototype),每一個原型對象都有一個指針constructor指向構(gòu)造函數(shù),每一個實例都有一個內(nèi)部指針(proto),指向原型對象,原型對象上的屬性和方法能被實例所訪問

繼承

類與類之間的關(guān)系 基類 父類 子類

//call&apply方法實現(xiàn)繼承
            function Person(name,age){
                this.name = name;
                this.age = age;
                this.sayHello = function (){
                    console.log(this.name);
                }
            }
            function Male(name,age){
                //繼承父類Person  call&apply 調(diào)用的是父類的構(gòu)造函數(shù)
//              Person.call(this,name,age);
                Person.apply(this,[name,age]);
            }
            var male = new Male("ly",20);
            male.sayHello();
            //這里不能用call&apply的原因是父類的構(gòu)造函數(shù)里邊什么也沒有 現(xiàn)在要調(diào)用的是父類的原型對象
            function Person(){
                
            }
            //Person.prototype里的屬性和方法可以被Person的實例訪問到
            Person.prototype.name = "jhon";
            Person.prototype.age = 20;
            Person.prototype.sayHello = function (){
                console.log(this.name);
            }
            function Male(){
                this.sayHi=function (){
                    console.log("aa")
                }
            }
            //Male.prototype.__proto__ 指向Person.prototype
            Male.prototype = new Person();
            //Male.prototype = Person.prototype;
            var male = new Male();
            male.sayHello();
            console.log(male.__proto__);//正常情況下應(yīng)該指向Male.prototype 但是現(xiàn)在指向Person.prototype
            //male.__proto__ -> Male.prototype   Male.prototype.__proto__ -> Person.prototype
            //當(dāng)male調(diào)用sayhello方法時會找到Male.prototype,如果Male.prototype沒有的話就會繼續(xù)向它的父類找,直到找到Object.prototype停止,Object.prototype.__proto__為null
            
            //原型鏈  原型鏈上的屬性和方法都能被實例所訪問到 
            
            console.log(male.__proto__ == Male.prototype);//true
            console.log(Male.prototype.__proto__ == Person.prototype);//true
            male.sayHi();
            var obj = {};
            //將其他類型轉(zhuǎn)換成字符串時,默認(rèn)會調(diào)用toString方法,這個方法是頂層原型對象上的方法,可以改寫,改寫之后,轉(zhuǎn)換的結(jié)果以改寫結(jié)果為準(zhǔn)
            obj.toString = function(){
                return 111111;
            }
            document.write(obj);//111111
### 組合繼承
            function Person(name,age){
                this.name = name;
                this.age = age;
            }
            Person.prototype.sayHello = function (){
                console.log(this.name);
            }
            function Male(name,age){
                Person.call(this,name,age);
            }
            //Male.prototype = new Person();
            //弊端在于Person.call的時候運行了一次構(gòu)造函數(shù)Person,當(dāng)Male.prototype = new Person()的時候又運行了一次
            
//          Male.prototype = Person.prototype;
//          //這時候Person.call指向的是Person里的name和age,而Male.prototype = Person.prototype指的是sayhello  弊端是這時候相當(dāng)于傳址,父類person的實例也能夠訪問到子類Male里的原型對象的方法,而這是不合道理的
//          Male.prototype.sayHi = function(){
//              console.log("aa");
//          }
//          var person = new Person();
//          person.sayHi();
            
            //遍歷person.prototype    call繼承實例屬性 這種方式繼承原型方法
            for(var i in Person.prototype){
                Male.prototype[i] = Person.prototype[i];
            }
            var male = new Male("ly",20);
            male.sayHello();

寄生式組合繼承 Object.create()

            var obj1 = {a:1};
            var obj2 = {b:2};
            var a = Object.create(obj1);
            console.log(a.__proto__);//結(jié)果是a:1  這時候的obj1是作為創(chuàng)建出來的實例a的原型對象存在 a.__proto__指obj1
            function Person(name,age){
                this.name = name;
                this.age = age;
            }
            Person.prototype.sayHello = function (){
                console.log(this.name);
            }
            function Male(name,age){
                Person.call(this,name,age);
            }
            Male.prototype = Object.create(Person.prototype);
            Male.prototype.constructor = Male;
            var male = new Male("ly",20);
            male.sayHello();
            console.log(male.__proto__.constructor);//本來應(yīng)該指向Male 但是現(xiàn)在指向了Person 需要加上Male.prototype.constructor = Male 讓它的原型對象指向自己

ES6繼承

            class Person{
                constructor(name,age){
                    this.name = name;
                    this.age = age;
                }
                sayHello(){
                    console.log(this.name);
                }
                //static 是一個靜態(tài)方法 也就是說foo可以認(rèn)為是這個構(gòu)造函數(shù)自帶的一個方法
                static foo(){
                    console.log("aa");
                }
            }
            console.log(Person.prototype)
            //用到exends關(guān)鍵字和super方法
            class Male extends Person{
                constructor(name,age){
                    //相當(dāng)于拿到了Person的this.name和this.age 同時改變了this指向
                    super(name,age)
                }
                sayHi(){
                    super.sayHello();
                }
            }
            var male = new Male("ly",20);
            male.sayHello();
            male.sayHi();//結(jié)果一樣
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容