原型俏讹、原型對象和繼承

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)系作者
  • 序言:七十年代末贤笆,一起剝皮案震驚了整個濱河市蝇棉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌芥永,老刑警劉巖篡殷,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異埋涧,居然都是意外死亡板辽,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門棘催,熙熙樓的掌柜王于貴愁眉苦臉地迎上來劲弦,“玉大人,你說我怎么就攤上這事醇坝∫毓颍” “怎么了?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵呼猪,是天一觀的道長画畅。 經(jīng)常有香客問我,道長宋距,這世上最難降的妖魔是什么轴踱? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮谚赎,結(jié)果婚禮上淫僻,老公的妹妹穿的比我還像新娘。我一直安慰自己沸版,他們只是感情好嘁傀,可當(dāng)我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著视粮,像睡著了一般细办。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蕾殴,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天笑撞,我揣著相機與錄音,去河邊找鬼钓觉。 笑死茴肥,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的荡灾。 我是一名探鬼主播瓤狐,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼瞬铸,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了础锐?” 一聲冷哼從身側(cè)響起嗓节,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎皆警,沒想到半個月后拦宣,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡信姓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年鸵隧,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片意推。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡豆瘫,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出菊值,到底是詐尸還是另有隱情靡羡,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布俊性,位于F島的核電站略步,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏定页。R本人自食惡果不足惜趟薄,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望典徊。 院中可真熱鬧杭煎,春花似錦、人聲如沸卒落。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽儡毕。三九已至也切,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間腰湾,已是汗流浹背雷恃。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留费坊,地道東北人倒槐。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像附井,于是被迫代替她去往敵國和親讨越。 傳聞我的和親對象是個殘疾皇子两残,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內(nèi)容