溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

JS面向?qū)ο?,?chuàng)建,繼承

發(fā)布時(shí)間:2020-07-27 08:19:02 來源:網(wǎng)絡(luò) 閱讀:276 作者:吳金瑞 欄目:網(wǎng)絡(luò)安全

1 創(chuàng)建一個(gè)面向?qū)ο?/strong>

JS面向?qū)ο?,?chuàng)建,繼承

var obj = new Object(); //創(chuàng)建一個(gè)空對(duì)象obj.name = 'haha';
obj.showName = function(){ 
   alert(obj.name);
}
obj.showName();

JS面向?qū)ο?,?chuàng)建,繼承

缺點(diǎn):當(dāng)我們想創(chuàng)建多個(gè)面向?qū)ο蟮臅r(shí)候,重復(fù)代碼過多,需要封裝,所以有了下面的方法

2  工廠方式

JS面向?qū)ο?,?chuàng)建,繼承

function CreatePerson(name){ 
    //原料
   var obj = new Object();    //加工
   obj.name = name;
   obj.showName = function(){ 
       alert(this.name);
   }   //出廠
   return obj;
}var p1 = CreatePerson('haha');
p1.showName();var p2 = CreatePerson('hehe');
p2.showName();

JS面向?qū)ο?,?chuàng)建,繼承

這其實(shí)就是簡(jiǎn)單的封裝函數(shù),整個(gè)過程像工廠的流水線,所以叫工廠方式

缺點(diǎn):無法識(shí)別創(chuàng)建的對(duì)象的類型。因?yàn)槿慷际荗bject,沒有區(qū)分度,不像Date、Array等,因此出現(xiàn)了構(gòu)造函數(shù)模式。

3 構(gòu)造函數(shù)模式

我們要通過這二個(gè)方面來改變:1 函數(shù)名首字母大寫  2 New 關(guān)鍵字調(diào)用

JS面向?qū)ο?,?chuàng)建,繼承

function CreatePerson(name){ 
     this.name = name; 
     this.showName = function(){ 
        alert(this.name); 
     } 
} 
var p1 =new CreatePerson('haha'); 
 p1.showName();var p2 = new CreatePerson('hehe');
 p2.showName();

JS面向?qū)ο?,?chuàng)建,繼承

1首字母大寫,是為了區(qū)別于普通的函數(shù),構(gòu)造函數(shù)本身就是普通的函數(shù),只是我們專門用它來實(shí)現(xiàn)了構(gòu)造的功能,所以專門起了一個(gè)名字叫構(gòu)造函數(shù),任何函數(shù)都可以成為構(gòu)造函數(shù),這取決于你調(diào)用函數(shù)的方式。是否用了New。

2 調(diào)用函數(shù)的時(shí)候用了 New關(guān)鍵字,那么New到底做了什么?用不用New有什么區(qū)別?再來看下面的例子

JS面向?qū)ο?,?chuàng)建,繼承

function CreatePerson(name){   
  this.name = name; 
  this.showName = function(){ 
    alert(this.name); 
  };
  console.log(this);
} 

new CreatePerson('haha'); //CreatePerson{}CreatePerson('haha');  //window

JS面向?qū)ο?,?chuàng)建,繼承

我們會(huì)發(fā)現(xiàn)當(dāng)用New去調(diào)用一個(gè)函數(shù)的時(shí)候,this的指向會(huì)不一樣。其實(shí)New主要做了下面這些事,不過下面寫的只是大概的行為,并不是內(nèi)部源碼。

JS面向?qū)ο?,?chuàng)建,繼承

function CreatePerson(name){   
  var res = {};  //聲明一個(gè)空對(duì)象res
  res._proto_= CreatePerson.prototype;//這個(gè)對(duì)象的_proto_屬性指向構(gòu)造函數(shù)的原型對(duì)象,這樣res就可以調(diào)用CreatePerson原型對(duì)象下的所有方法
  CreatePerson.apply(res);//把this指向改為res對(duì)象
  this.name = name;  //res對(duì)象添加屬性,方法
  this.showName = function(){ 
    alert(this.name); 
  };  return res;//返回這個(gè)對(duì)象}

JS面向?qū)ο?,?chuàng)建,繼承

關(guān)于New做時(shí)候都是內(nèi)部的行為,看不到但確實(shí)存在,關(guān)于上面原型可以先大概知道結(jié)論,下面會(huì)說原型,接著看就懂了。

函數(shù)構(gòu)造模式存在的問題:

alert(p1.showName==p2.showName);//false

測(cè)試這個(gè)代碼,兩個(gè)方法是不相同的,也就是說這兩個(gè)對(duì)象并不是共用一個(gè)方法,每new一次,系統(tǒng)都會(huì)新創(chuàng)建一個(gè)內(nèi)存,這兩個(gè)對(duì)象各自有各自的地盤,但他們具有相同的功能,還不共用,肯定不是我們所希望的。所以就有了下一種方法,原型+構(gòu)造模式

4 原型+構(gòu)造模式

每個(gè)函數(shù)都有一個(gè)prototype屬性,它是一個(gè)對(duì)象,也稱作原型對(duì)象,這個(gè)原型對(duì)象,我們可以把方法和屬性寫在它上面(不過原型對(duì)象不僅僅有我們寫的屬性和方法,還有別的,下面會(huì)介紹),而通過這個(gè)函數(shù)創(chuàng)建出來的實(shí)例對(duì)象,都能共享這個(gè)原型對(duì)象下的方法和屬性。所以我們只需要把想要共享的東西放在函數(shù)的prototype下,不想共享的東西通過構(gòu)造函數(shù)來創(chuàng)建就可以了。

看個(gè)栗子(原型+構(gòu)造)

JS面向?qū)ο?,?chuàng)建,繼承

function CreatePerson(name){ 
    this.name = name;
}CreatePerson.prototype.showName = function(){ 
    alert(this.name);
}
var p1 =new CreatePerson('haha');
p1.showName();
var p2 = new CreatePerson('hehe');
p2.showName();

alert(p1.showName==p2.showName);//true

JS面向?qū)ο?,?chuàng)建,繼承

    通過最后一句的測(cè)試為true,可以看到在構(gòu)造函數(shù)的原型下面加的方法showName()方法是所有通過這個(gè)構(gòu)造函數(shù)創(chuàng)建出來的對(duì)象所共享的,也就是說他們共用一個(gè)內(nèi)存,更進(jìn)一步的說它們存在引用關(guān)系,也就是說你更改了p1的showName也會(huì)影響p2的showName。

    所以我們?cè)跇?gòu)造對(duì)象的時(shí)候,一般是原型模式和構(gòu)造模式組合使用,變化的用構(gòu)造模式 不變的公用的用原型模式,就像上面的這個(gè)栗子,屬性用的構(gòu)造函數(shù),因?yàn)橐话悴煌瑢?duì)象屬性都不同,方法用原型模式。

 _proto_屬性:同一個(gè)函數(shù)造出來的實(shí)例對(duì)象能共享這個(gè)函數(shù)的prototype下的方法和屬性,但是它是如何做到的呢?這里要出場(chǎng)的就是_proto_屬性,每個(gè)實(shí)例化對(duì)象都有一個(gè)_proto_屬性,它是一個(gè)指針,指向函數(shù)的prototype,也就是保存了它的地址。(JS中任何對(duì)象的值都是保存在堆內(nèi)存中,我們聲明的變量只是一個(gè)指針,保存了這個(gè)對(duì)象的實(shí)際地址,所以有了地址就能找到對(duì)象),所以總得來說,每個(gè)實(shí)例化對(duì)象都有_proto_屬性,保存了構(gòu)造函數(shù)的原型對(duì)象的地址,通過這個(gè)屬性就可以擁有原型對(duì)象下的所有屬性和方法,_proto_屬性實(shí)際就是實(shí)例化對(duì)象和原型對(duì)象之間的連接。

原型鏈: 每個(gè)函數(shù)都可以成為構(gòu)造函數(shù),每個(gè)函數(shù)都有原型對(duì)象,每個(gè)原型對(duì)象也可以是一個(gè)實(shí)例化對(duì)象,比如,你創(chuàng)建了一個(gè)函數(shù)fun,它是構(gòu)造函數(shù)function的實(shí)例化對(duì)象,而function的原型對(duì)象,又是Object的實(shí)例對(duì)象。所以fun有個(gè)_proto_屬性可以訪問到function的原型對(duì)象,function原型對(duì)象也是個(gè)實(shí)例對(duì)象,也有個(gè)_proto_屬性,可以訪問到Object的原型對(duì)象,所以通過_proto_屬性,就形成了一條原型鏈。每個(gè)實(shí)例化對(duì)象都可以訪問到鏈子上方的方法和屬性,所以fun是可以訪問Object原型對(duì)象下的方法和屬性的。實(shí)際上所有對(duì)象都可以訪問到Object的原型對(duì)象。

原型鏈的訪問規(guī)則:先在自身的下面尋找,再去一級(jí)一級(jí)的往原型鏈上找。如下:

JS面向?qū)ο螅瑒?chuàng)建,繼承

function Aaa(){}
Aaa.prototype.num = 3;var a1 = new Aaa();
a1.num =10;
alert(a1.num); //10

JS面向?qū)ο螅瑒?chuàng)建,繼承

JS面向?qū)ο?,?chuàng)建,繼承

原型對(duì)象下的方法和屬性:原型對(duì)象下面可能有三大類:1 原型對(duì)象所帶方法和屬性   2 constructor   3 _proto_

constructor:構(gòu)造函數(shù)屬性,每個(gè)函數(shù)的原型對(duì)象都有的默認(rèn)屬性,指向函數(shù)。每個(gè)實(shí)例化對(duì)象本身是沒有constructor屬性的,每個(gè)實(shí)例化對(duì)象下面都默認(rèn)只有一個(gè)_proto_,用來連接原型對(duì)象,而和構(gòu)造函數(shù)本身是沒有直接的聯(lián)系的。所以它的constructor是訪問的原型對(duì)象上的。所以當(dāng)原型對(duì)象的constructor變化了,實(shí)例化對(duì)象的constructor也會(huì)改變。但是如果這個(gè)對(duì)象本身既是原型對(duì)象,又是實(shí)例化對(duì)象,那就擁有了constructor屬性,無需從原型對(duì)象繼承。

看下面的例子,來驗(yàn)證我們所說的:

JS面向?qū)ο?,?chuàng)建,繼承

.name ==  p1 = CreatePerson('haha'console.log(CreatePerson.prototype.__proto__===Object.prototype);console.log(CreatePerson.prototype.__proto__===Object);console.log(CreatePerson.constructor); console.log(CreatePerson.prototype  CreatePerson )

JS面向?qū)ο?,?chuàng)建,繼承

字面量法定義原型

為了創(chuàng)建對(duì)象的代碼更方便,你一定見過這樣的代碼,就是字面量法:

JS面向?qū)ο?,?chuàng)建,繼承

function Aaa(){}
Aaa.prototype = {
    showName:function(){alert(10);}
}; var a1 = new Aaa();
console.log(Aaa.prototype);//{showName:function(){},_proto_}   你會(huì)發(fā)現(xiàn)constructor不見了,因?yàn)檫@種方式相當(dāng)于重新賦值了Aaa.prototype console.log(Aaa.prototype.constructor);//Object  因?yàn)樽陨頉]有了constructor屬性,就去上級(jí)原型對(duì)象找,找到了Objectconsole.log(a1.constructor );//Object 也變了,驗(yàn)證了它是訪問的原型對(duì)象上的

JS面向?qū)ο?,?chuàng)建,繼承

因此我們?cè)趯懙臅r(shí)候需要修正一下原型的指向:

JS面向?qū)ο螅瑒?chuàng)建,繼承

function Aaa(){}
Aaa.prototype = {
  constructor:Aaa,
  num1:function(){alert(10);}
} 
var a1 = new Aaa(); 
a1.constructor // Aaa

JS面向?qū)ο螅瑒?chuàng)建,繼承


向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI