摘要:面向?qū)ο蠡A(chǔ)在的時(shí)候發(fā)生了什么大家在日常的開發(fā)中,會(huì)經(jīng)常見到類似于下面的代碼塊大黃黃色到這邊的話,我們就成功創(chuàng)建了一個(gè)類的對(duì)象。參考面向?qū)ο缶幊桃环庋b面向?qū)ο缶幊潭庋b面向?qū)ο缶幊倘菢?gòu)造函數(shù)的繼承
js面向?qū)ο蠡A(chǔ) javascript在new xxx的時(shí)候發(fā)生了什么?
大家在日常的js開發(fā)中,會(huì)經(jīng)常見到類似于下面的代碼塊:
function Cat(name,color){ this.name = name; this.color = color; } Cat.prototype.sayName = function(){ console.log("this cat name is:"+this.name); } Cat.prototype.sayAge = function(){ console.log("this cat age is:"+this.age); } var cat = new Cat("大黃","黃色");
到這邊的話,我們就成功創(chuàng)建了一個(gè)Cat類的對(duì)象cat。(注意下,雖然這邊我們?nèi)匀徽勵(lì)?,但是由于JS是一門鴨子類型的語言,只要具備某個(gè)類一定的特性,比如某些方法、屬性,那么我們就認(rèn)為這個(gè)對(duì)象就是這個(gè)類的)
那么在cat對(duì)象的創(chuàng)建過程中,又發(fā)生了那些事情呢?創(chuàng)建一個(gè)對(duì)象,一般會(huì)經(jīng)歷如下幾個(gè)步驟:
創(chuàng)建一個(gè)空對(duì)象o
令o的原型指向函數(shù)的原型
在新創(chuàng)建的對(duì)象o上執(zhí)行函數(shù),即function.apply(o,arguments)
返回對(duì)象o
經(jīng)過以上四個(gè)步驟我們就可以創(chuàng)實(shí)例化一個(gè)Cat類型的對(duì)象。
這里說個(gè)大家比較容易出錯(cuò)的地方,就是function優(yōu)惠返回值的情況。比如:
function F(name){ this.name = name; return "F"; }
這邊如果執(zhí)行var f = new F("warjiang");js在new F("warjiang")的時(shí)候回忽略F的返回值。f最后是一個(gè)對(duì)象,而不是"F".執(zhí)行結(jié)果如下:
什么時(shí)候用prototype,什么時(shí)候用this?接著上面的例子,我們?cè)诙xCat類的時(shí)候,對(duì)于name,color這些屬性的定義是采用的this的方式。而對(duì)于sayName,sayAge的定義是采用的prototype的方式。那么什么時(shí)候該用this,什么時(shí)候該用prototype呢?在說這個(gè)問題之前,我想重新再提一下==,===。相信每個(gè)jser都應(yīng)該知道這個(gè)兩個(gè)等號(hào)與三個(gè)等號(hào)的區(qū)別,兩個(gè)等號(hào)只比較數(shù)值大小,不關(guān)心類型;三個(gè)等號(hào)不僅比較值大小,還要比較類型是否一致。下面我們先看個(gè)例子:
// number類型 var num1 = 22; var num2 = 22; console.log(num1 == num2);//true console.log(num1 === num2);//true // string類型 var str1 = "hello world"; var str2 = "hello world"; console.log(str1 == str2)//true console.log(str1 === str2)//true // 對(duì)象 var student1 = { name:"tony", age:22 }; var student2 = { name:"warjiang", age:22 } console.log(student1 == student2);//false console.log(student1 === student2);//false // Date類型 var d1 = new Date("2017-3-15 10:23:00"); var d2 = new Date("2017-3-15 10:23:00"); console.log(d1 == d2);//false console.log(d1 === d2);//false; // 自定義類型 function Cat(name,color){ this.name = name; this.color = color; } Cat.prototype.sayName = function(){ console.log("my name is " + this.name); } var cat1 = new Cat("大黃","黃色"); var cat2 = new Cat("大黃","黃色"); console.log(cat1 == cat2);//false console.log(cat1 === cat2);//false
通過上面的例子,我們可以總結(jié)出,在js中除了基本類型bool,string,number,undefined,null是按照value的方式進(jìn)行相等的比較之外,其余的對(duì)象(不管是自定義的還是JS內(nèi)置的)在做比較的時(shí)候都是比較兩個(gè)對(duì)象的內(nèi)存地址,如果兩個(gè)對(duì)象的內(nèi)存地址不相等,則表示兩個(gè)對(duì)象就是不相等的。所以才會(huì)出現(xiàn)上面例子中的,即使連個(gè)對(duì)象中所有的屬性都相等,仍然會(huì)出現(xiàn)兩個(gè)對(duì)象不相當(dāng)?shù)那闆r。
ok回到正題上了,有了這邊等號(hào)比較的基礎(chǔ)之后,我們?cè)趤砜纯粗暗膯栴},什么時(shí)候應(yīng)該使用prototype,什么時(shí)候應(yīng)該使用this。再來個(gè)?
function Cat(name,color){ this.name = name; this.color = color; this.sayColor = function(){ console.log(this.color); } } Cat.prototype.sayName = function(){ console.log("my name is:"+this.name); } var cat1 = new Cat("大黃","黃色"); var cat2 = new Cat("大白","白色"); console.log(cat1.sayColor == cat2.sayColor);//false console.log(cat1.sayName == cat2.sayName);//true
上面例子中兩個(gè)Cat類型的對(duì)象cat1,cat2在內(nèi)存中是什么情況呢。
通過上面的內(nèi)存圖,我們可以知道cat1的sayColor與cat2的sayColor方法分別指向兩塊內(nèi)存地址,所以cat1.sayColor==cat2.sayColor為false,而cat1.sayName與cat2.sayName都是來源于prototype對(duì)象上的sayName方法,他們的內(nèi)存地址其實(shí)是一個(gè),故而cat1.sayName == cat2.sayName方法為true。
通過上面的兩個(gè)例子,我們不難看出,如果我們使用this的話,則this上的屬性、方法都是屬于對(duì)象本身的,一般可以用于私有方法、屬性,而如果使用prototype的話,prototype上的屬性、方法在各個(gè)類對(duì)象上面共享,一般可以用于共有方法、屬性。
因此對(duì)于一些共有的方法、屬性,我們可以放在prototype上面,而對(duì)于一些私有的方法、屬性,我們可以放在prototype上
下面的話,我再補(bǔ)充一個(gè)額外的例子
function Cat(name,color){ this.name = name; this.color = color; } Cat.prototype.type = "貓科動(dòng)物"; Cat.prototype.sayType = function(){ console.log(this.type); } var cat1 = new Cat("大黃","黃色"); var cat2 = new Cat("大白","白色"); cat1.sayType();//貓科動(dòng)物 cat1.type = "狗科動(dòng)物"; cat2.sayType();//貓科動(dòng)物 cat1.sayType();//狗科動(dòng)物
這邊的話,可能有些同學(xué)會(huì)認(rèn)為cat1.type = "狗科動(dòng)物"這句話,修改的是prototype中的type,但是實(shí)際上cat1.type="狗科動(dòng)物",只是在cat1對(duì)象上面增加了一個(gè)type屬性,值為"狗科動(dòng)物",而原型上面的type并沒有收到影響。我們可以在控制臺(tái)中查看cat1與cat2的詳細(xì)如下:
如果想修改prototype中的type的話,可以把cat1.type修改為cat1.__proto__.type = "狗科動(dòng)物"(這邊也要注意下,__proto__并不是所有瀏覽器都支持);此時(shí)執(zhí)行結(jié)果就像大家想的那樣分別為貓科動(dòng)物,狗科動(dòng)物,狗科動(dòng)物。
談到j(luò)s的繼承,首先先了解下js中原型鏈。每個(gè)js對(duì)象都有一個(gè)prototype的屬性,這個(gè)屬性會(huì)指向一個(gè)新的對(duì)象,這個(gè)新的對(duì)象也會(huì)有一個(gè)prototype的屬性。這樣一直到Object.
這邊稍微提下,有些人可能會(huì)問瀏覽器中__proto__與prototype的區(qū)別,可以理解為__proto__是chrome、firefox這些瀏覽器對(duì)prototype的一種實(shí)現(xiàn)、表現(xiàn),東西還是一個(gè)東西。原型鏈我也舉個(gè)例子
var o = { name:"warjiang", age:24 } var b = { name:"bb" } b.__proto__ = o; console.log(b.name);//bb console.log(b.age);//24 console.log(b.__proto__.name);//warjiang
講完原型鏈,我們就開始開始講講繼承。這邊的話,我看也有人說用屬性拷貝或者是方法借用這種方式來實(shí)現(xiàn)繼承,不過我不是非常認(rèn)可。這邊我主要用講原型來實(shí)現(xiàn)繼承。
用原型鏈實(shí)現(xiàn)繼承,就是讓子類的prototype指向父類的prototype,比如下面這樣:
function Parent(){ this.type = "parent"; } Parent.prototype.sayType = function(){ console.log(this.type); } function Child(){ } Child.prototype = Parent.prototype; Child.prototype.constructor = Child;
但是如果這樣寫會(huì)有一個(gè)問題,就是我們?cè)谛薷淖宇恜rototype的constructor的同時(shí)也修改了父類的prototype的constructor,這種情況是不允許的。那么解決的思路一般就是兩種,一個(gè)是通過new Parent()來解決,我們知道new Parent()的過程幫我們創(chuàng)造一個(gè)prototype指向Parent的prototype的對(duì)象(記作o,o.prototype=parent.prototype),這個(gè)時(shí)候,讓子類prototype指向o這個(gè)對(duì)象的時(shí)候,Child.prototype->o,o.prototype->Parent.prototype,這樣一個(gè)原型鏈就這么鏈接起來了,同時(shí)這個(gè)時(shí)候如果去修正Child.prototype.constructor為Child的時(shí)候,相當(dāng)于執(zhí)行o.constructor = Child,并不會(huì)對(duì)Parent.prototype造成影響。這種做法的表現(xiàn)形式如下:
function Parent(){ this.type = "parent"; } Parent.prototype.sayType = function(){ console.log(this.type); } function Child(){ } Child.prototype = new Parent(); Child.prototype.constructor = Child;
此時(shí)如果我們?nèi)ew Child()對(duì)象的時(shí)候,我們可以如下的繼承圖
分析Child.prototype=new Parent();這個(gè)過程我們會(huì)發(fā)現(xiàn),new Parent()其實(shí)對(duì)Parent的prototype起到保護(hù)的作用,因此我們完全可以通過一個(gè)空對(duì)象來完成這樣的功能,如下:
function Parent(){ this.type = "parent"; } Parent.prototype.sayType = function(){ console.log(this.type); } var f = function(){} f.prototype = Parent.prototype; function Child(){ } Child.prototype = new f(); Child.prototype.constructor = Child;
這么做的好處在于new f()的過程相對(duì)于new Parent()的過程更加輕量,更加節(jié)約內(nèi)存。
參考Prototye inheritance
Javascript 面向?qū)ο缶幊蹋ㄒ唬悍庋b
Javascript 面向?qū)ο缶幊蹋ǘ悍庋b
Javascript面向?qū)ο缶幊蹋ㄈ悍菢?gòu)造函數(shù)的繼承
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/88197.html
摘要:面向?qū)ο笕筇卣骼^承性多態(tài)性封裝性接口。第五階段封裝一個(gè)屬于自己的框架框架封裝基礎(chǔ)事件流冒泡捕獲事件對(duì)象事件框架選擇框架。核心模塊和對(duì)象全局對(duì)象,,,事件驅(qū)動(dòng),事件發(fā)射器加密解密,路徑操作,序列化和反序列化文件流操作服務(wù)端與客戶端。 第一階段: HTML+CSS:HTML進(jìn)階、CSS進(jìn)階、div+css布局、HTML+css整站開發(fā)、 JavaScript基礎(chǔ):Js基礎(chǔ)教程、js內(nèi)置對(duì)...
摘要:面向?qū)ο笕筇卣骼^承性多態(tài)性封裝性接口。第五階段封裝一個(gè)屬于自己的框架框架封裝基礎(chǔ)事件流冒泡捕獲事件對(duì)象事件框架選擇框架。核心模塊和對(duì)象全局對(duì)象,,,事件驅(qū)動(dòng),事件發(fā)射器加密解密,路徑操作,序列化和反序列化文件流操作服務(wù)端與客戶端。 第一階段: HTML+CSS:HTML進(jìn)階、CSS進(jìn)階、div+css布局、HTML+css整站開發(fā)、 JavaScript基礎(chǔ):Js基礎(chǔ)教程、js內(nèi)置對(duì)...
摘要:面向?qū)ο笕腴T基礎(chǔ)我們?cè)谌粘>幊讨?,用到的大多都是面向過程的編程,但是的編程我們要運(yùn)到面向?qū)ο?,?chuàng)建對(duì)象實(shí)例類,下邊說一下,我們創(chuàng)建對(duì)象的幾種方法我們創(chuàng)建對(duì)象有下邊幾種方法第一個(gè)方法第二種方法直接創(chuàng)建一個(gè)對(duì)象,字面量形式上邊的方法我們經(jīng)常用來 js面向?qū)ο笕腴T基礎(chǔ) 我們?cè)谌粘>幊讨?,用到的大多都是js面向過程的編程,但是20%的編程我們要運(yùn)到面向?qū)ο螅瑒?chuàng)建對(duì)象實(shí)例(類),下邊說一下,我們...
摘要:對(duì)象對(duì)象的定義對(duì)象是由鍵值對(duì)組成的無序集合。創(chuàng)建對(duì)象兩種方法方法一字面量方法方法二構(gòu)造函數(shù)創(chuàng)建面向?qū)ο蠛兔嫦蜻^程的比較如果想要把大象放進(jìn)冰箱。 1.對(duì)象 對(duì)象的定義 : 對(duì)象 是 由 鍵值對(duì) 組成的無序集合。 創(chuàng)建對(duì)象兩種方法 : 方法一 : 字面量方法 var obj = {name: k}; 方法二 : new Object( ) 構(gòu)造函數(shù)創(chuàng)建 var a = n...
摘要:對(duì)象對(duì)象的定義對(duì)象是由鍵值對(duì)組成的無序集合。創(chuàng)建對(duì)象兩種方法方法一字面量方法方法二構(gòu)造函數(shù)創(chuàng)建面向?qū)ο蠛兔嫦蜻^程的比較如果想要把大象放進(jìn)冰箱。 1.對(duì)象 對(duì)象的定義 : 對(duì)象 是 由 鍵值對(duì) 組成的無序集合。 創(chuàng)建對(duì)象兩種方法 : 方法一 : 字面量方法 var obj = {name: k}; 方法二 : new Object( ) 構(gòu)造函數(shù)創(chuàng)建 var a = n...
閱讀 2444·2021-09-22 15:41
閱讀 1458·2021-08-19 10:54
閱讀 1768·2019-08-23 15:11
閱讀 3407·2019-08-23 10:23
閱讀 1434·2019-08-22 16:28
閱讀 804·2019-08-22 15:11
閱讀 746·2019-08-22 14:53
閱讀 720·2019-08-22 13:49