摘要:構(gòu)造函數(shù)構(gòu)造操作符調(diào)用的函數(shù)就是構(gòu)造函數(shù)。其和其構(gòu)造函數(shù)的指向相同。而構(gòu)造函數(shù)屬性指向的對象帶有屬性,指向函數(shù)自身。,回歸構(gòu)造函數(shù)繼承,仔細(xì)看看誕生的嘻嘻和哈哈兩位同學(xué)可以看到兩個實例都擁有了和兩個屬性,因為方法的運行類似于執(zhí)行了和。
最近在看《JavaScript設(shè)計模式》,然后開篇復(fù)習(xí)了JavaScript中的幾種繼承方式,自己似乎也沒有怎么仔細(xì)探究過,目前自己沒怎么碰到過應(yīng)用的場景(噗),所以借這次機會好好來屢屢思路。
方式1 類式繼承例子
function Person() { this.telephone = ["000-0000-0000"]; } function Student(className) { this.className = className; } Student.prototype = new Person(); var Haha = new Student(1); var Xixi = new Student(2);
創(chuàng)建好父類和子類。聯(lián)系他們的方式是把學(xué)生的prototype指向一個人的實例。
問:prototype是什么?
幾乎任何對象有一個[[prototype]]屬性,在標(biāo)準(zhǔn)中,[[prototype]]一個隱藏屬性,指向的是這個對象的原型。而它的指向是由構(gòu)造該對象的方法決定的:
1.對象字面量構(gòu)造:其[[prototype]]指向Object.prototype。
var person = {};
2.構(gòu)造函數(shù)構(gòu)造:new操作符調(diào)用的函數(shù)就是構(gòu)造函數(shù)。其[[prototype]]和其構(gòu)造函數(shù)的prototype指向相同。而構(gòu)造函數(shù)prototype屬性指向的對象帶有constructor屬性,指向函數(shù)自身。
function Person(){} var person = new Person();
此圖為Person的prototype內(nèi)容,可以看到constructor屬性實際指向的就是Person()函數(shù)。(小綠色框框內(nèi)和外面綠色框框其實是同一個內(nèi)容)。
3.Object.create構(gòu)造的。
var person = {}; var Haha = Object.create(person);
這里對象Haha的[[prototype]]指向?qū)ο髉erson。也可以寫null,此時對象Haha就沒有原型。
首先要分清楚類和實例,在控制臺顯示中,只有類才會有prototype屬性,而實例是擁有一個名為_proto_的屬性,它會指向構(gòu)造它函數(shù)的原型,兩者本質(zhì)都是一個指針。
function Person() { this.telephone = ["000-0000-0000"]; } var Hehe = new Person(); console.log(Person.prototype); console.log(Hehe);
以上代碼運行結(jié)果:
可以瞧見,這里Hehe的_proto_是指向了Person.prototype。
問:new關(guān)鍵字的作用是什么?
new關(guān)鍵字運作的過程如下,引用自《JavaScript》高級程序設(shè)計:
1、創(chuàng)建一個空對象,并且 this 變量引用該對象,同時還繼承了該函數(shù)的原型。 2、屬性和方法被加入到 this 引用的對象中。
3、新創(chuàng)建的對象由 this 所引用,并且最后隱式的返回 this。
簡單來說,它創(chuàng)建了一個空對象,指定了原型,把屬性方法進(jìn)行拷貝,并把this指向進(jìn)行了改變。假如我們把上面的代碼改成:
function Person() { this.telephone = ["000-0000-0000"]; } var Hehe = Person(); console.log(Hehe.telephone);
去掉new關(guān)鍵詞賦予Person(),會報錯,而輸出window.telphone得到的就是["000-0000-0000"]。因為函數(shù)的返回值(沒有返回值所以是undefined)賦予給了Hehe,嘗試去讀取undefined的屬性,報錯了。而此時函數(shù)運行中的this是全局變量window。
So,回歸類式繼承,仔細(xì)看看誕生的嘻嘻和哈哈兩位同學(xué)
會發(fā)現(xiàn),各自都有自己的班級名屬性,但是原型指向的是同一個Person實例,所以如果嘻嘻有兩個號碼,或者他要更改自己的號碼,那哈哈的電話號碼也會發(fā)生變化,他們只能共享這個電話號碼。
方式2 構(gòu)造函數(shù)繼承例子
function Person(name) { this.name = name; } Person.prototype.showName = function() { console.log(this.name); } function Student(name, className) { this.className = className; Person.call(this, name); } var Haha = new Student("Haha", 1); var Xixi = new Student("Xixi", 2);
問:call函數(shù)的運作過程?
call函數(shù)和apply函數(shù)的作用相同,不同之處就是apply函數(shù)只能傳入2個參數(shù),而call函數(shù)可以有多個。F.call(thisArg,[arg1……]) 函數(shù)的運作過程如下(來源網(wǎng)絡(luò)):
1.先判斷F是否為一個函數(shù),如果不是一個函數(shù),那么將拋出TypeError異常。
2.創(chuàng)建一個內(nèi)部類型空列表list
3.然后如果參數(shù)除去thisArg外還有其他參數(shù)的話,就將這些值添加到list中
4.thisArg和list作為F內(nèi)部屬性[[Call]]的參數(shù)傳入調(diào)用進(jìn)行函數(shù)的執(zhí)行操作
簡而言之就是它把一個函數(shù)的對象上下文改成了由 thisArg指定的新對象。
So,回歸構(gòu)造函數(shù)繼承,仔細(xì)看看誕生的嘻嘻和哈哈兩位同學(xué)
可以看到兩個實例都擁有了className和name兩個屬性,因為call方法的運行類似于執(zhí)行了Haha.name="Haha"和Xixi.name="Xixi"。
但是因為沒有與父類的原型相聯(lián)系,所以父類原型中的方法,不能得到繼承。運行Haha.showName()會得到報錯。
例子
function Person(name) { this.name = name; } Person.prototype.showName = function() { console.log(this.name); } function Student(name, className) { this.className = className; Person.call(this, name); } Student.prototype = new Person(); Student.prototype.showClassName = function() { console.log(this.className); } var Haha = new Student("Haha", 1); var Xixi = new Student("Xixi", 2);
組合繼承綜合了類式繼承和構(gòu)造函數(shù)繼承,在把父類的屬性繼承后,把子類的原型指向了父類實例,這樣就可以繼承父類原型的方法了。
但是這里相當(dāng)于使用了兩次父類函數(shù),并且子類不是父類的實例,子類的原型是父類的實例,所以還會有更好的方法。
function inheritObject(o) { function F() {} F.prototype = o; return new F(); } var person = { name: "unknown", telephone: ["000-0000-0000"] } var Xixi = inheritObject(person); Xixi.name = "Xixi"; Xixi.telephone.push("111-1111-1111"); var Haha = inheritObject(person); Haha.name = "Haha";
仔細(xì)看看誕生的嘻嘻和哈哈兩位同學(xué)
這里.name給Xixi實例添加了一個自己的name屬性,而push操作是直接影響原型中引用變量,所以改進(jìn)之后又有了下面這種方式。
在這里我產(chǎn)生了一個疑問,為什么name屬性是自己添加新的,而telephone是采用原來的。于是添加了一個age屬性,執(zhí)行Xixi.age++操作。
這里可以看到實例重新添加了一個age屬性,所以我們可以說只要是改變原型屬性的值,就會把新的屬性加在實例上,引用不改變是因為引用的地址還沒有改變。
方式5 寄生式繼承寄生式繼承是在原型繼承的基礎(chǔ)之上,我們需要再添加一下代碼:
function createPerson(obj) { var o = inheritObject(obj); o.getName = function(){ console.log(name); } return o; }
這樣就給得到的對象添加了公共方法。
方式6 寄生組合式繼承寄生組合式繼承是為了彌補組合式繼承的缺點,是在寄生式繼承+構(gòu)造函數(shù)繼承組合而成的:
function inheritObject(o) { function F() {} F.prototype = o; return new F(); } function inheritPrototype(subClass, superClass) { //復(fù)制一份父類原型 var p = inheritObject(superClass.prototype); //修正重寫子類原型導(dǎo)致constructor屬性被修改 p.constructor = subClass; //設(shè)置子類原型 subClass.prototype = p; } function Person(name) { this.name = name; } Person.prototype.showName = function() { console.log(this.name); } function Student(name, className) { this.className = className; Person.call(this, name); } inheritPrototype(Student, Person); Student.prototype.showClassName = function() { console.log(this.className); } var Xixi = new Student("Xixi",2); var Haha = new Student("Haha",1);
以下為嘻嘻和哈哈的內(nèi)容:
可以對比一下組合式繼承的結(jié)果:
不同的地方在于把子類原型的構(gòu)造函數(shù)改成了實例對應(yīng)的構(gòu)造函數(shù),在組合繼承中子類原型直屬并沒有constructor屬性。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/93124.html
摘要:為什么會產(chǎn)生閉包究其根本,是因為代表的函數(shù)包含的作用域。而在作用域鏈中,外部函數(shù)的活動對象始終處于第二位,外部函數(shù)的外部函數(shù)的活動對象處于第三位直到作為作用域鏈終點的全局執(zhí)行環(huán)境。 前言 此文的內(nèi)容主要是來自看書的總結(jié)+小小的實踐哦~會不斷更新總結(jié)。 什么是閉包 書上是這樣定義閉包的: 有權(quán)訪問另一個函數(shù)作用域中變量的函數(shù)。 舉一個例子: function test(){ va...
摘要:問題起源以前一直就聽說圣杯布局,但是沒有怎么去用過,然后這次偶然接觸到了,就學(xué)習(xí)了一下。繼續(xù)試驗我們可以嘗試改變的值,去看看位置的變化。為了方便我們計算,另外寫了一個類似的布局,內(nèi)容區(qū)的寬度是,三個的寬度也都是。 問題の起源 以前一直就聽說圣杯布局,但是沒有怎么去用過,然后這次偶然接觸到了,就學(xué)習(xí)了一下。這是一個我從別人寫的文章中復(fù)制過來的,關(guān)于圣杯布局的比較簡單的說明 通過縮放頁面就...
摘要:官方默認(rèn)項目是存放了一個為的打開文件夾有一個,還有一個名為組件的文件夾,里面放了一個文件。部分我們會發(fā)現(xiàn)這幾排字就是顯示在頁面的幾排文字部分這其中的這個文件引入了,還有上述的。結(jié)合查詢其他說法,就是說它會把是的元素以形式替換。 前言 我很早就想來學(xué)習(xí)學(xué)習(xí)vue.js啦,終于有了那么一些空閑的時間可以拿來學(xué)習(xí),于是從前天開始我就每天抽一個多小時來體驗vue.js。當(dāng)然啦,因為是小白入門,...
閱讀 688·2021-11-25 09:43
閱讀 2958·2021-11-24 10:20
閱讀 1012·2021-10-27 14:18
閱讀 1082·2021-09-08 09:36
閱讀 3390·2021-07-29 14:49
閱讀 1788·2019-08-30 14:07
閱讀 2942·2019-08-29 16:52
閱讀 3053·2019-08-29 13:12