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