一、對象數組
在傳統的面向過程的程序設計中,會形成函數或變量的冗餘。而JS中對象的目的是將全部的具備相同屬性或行爲的代碼整合到一塊兒,造成一個集合,這樣就會方便咱們管理,例如:函數
var person1={
name:"tan",
age:26,
showMessage:function(){
alert("name:"+this.name);
}
};
person.showMessage();//輸出name:tanthis
以上的例子將name、age、showMessage放進person1這個對象中,方便了咱們的管理同時也減小了咱們的命名困難。.net
咱們下面的講解會用到的基本知識點:prototype
1)、內存會對每個對象一個內存空間;設計
2)、函數也是一個對象。指針
每個對象都會佔據必定的內存空間。對象
二、構造函數blog
以上能夠看出對象的產生方便了咱們的代碼管理,可是又產生了一個問題,若是我又定義了一個對象person2,以下:繼承
var person1={
name:"song",
age:16,
showMessage:function(){
alert("name:"+this.name);
}
};
這樣就產生了代碼的重複問題——person1與person2有一樣的屬性和行爲,是否是能經過創造一個函數經過傳參來改變對象的屬性值,這樣就引出了構造函數的概念。
function Person(name,age)={
this.name=name;
this.age=age;
this.showMessage=function(){
alert("name:"+this.name);
};
}
var person1=new Person(tan,26);
var person2=new Person(song,16);
這樣經過構造函數咱們就不用反覆去從新定義屬性和行爲,咱們就創造了兩個對象person1和person2。person1和person2也叫做構造函數Person的兩個實例。
三、原型
看上去構造函數能夠完美的解決咱們的代碼管理和重複性的問題。可是,正如在1中提到的函數也是一個對象,也會有必定的內存空間,屬性咱們能夠容忍每個對象佔據一個空間,但方法也就是行爲,他對每個對象來講動做是同樣的,只是可能的參數不同。所以咱們要想一個方法來解決內存空間被過多的佔用的問題。
擬解決方法1:函數的定義轉移到構造函數外,例如:
function Person(name,age)={
this.name=name;
this.age=age;
this.showMessage=showMessage;
}
function showMessage(){
alert("name:"+name);
}
這時構造函數中this.showMessage會指向showMessage這個全局變量,先在構造函數的內部去找showMessage這個變量,而後去外部找(涉及到了做用域鏈的問題之後再說)。
這個解決方案看似很好,但一個對象如有多個方法時,代碼的封裝性沒法體現,並且全局的函數只是爲一個對象服務,則全局性體現的不明顯。
擬解決方法2:原型
首先要知道,每個函數在建立的時候都會默認的分配一個prototype屬性,構造函數也不例外。那麼 prototype屬性是什麼?
prototype是一個指針,它指向一個對象。指針就像是我想到存一本書在一間房子裏(這是一個行爲),我要完成這個行爲,我先要建房子而後把書放進房子裏,我下次要存一本新書,那麼我還要先建房子在放另外一本書,是否是聽起來很麻煩,那麼更好的解決方法呢?整個行爲房子是一個肯定的動做,不須要每次都重建,我建一次把房子的地址記下來,之後我每一次有放書這個動做時只須要經過地址找到對應的房子就好了。如上面的例子showMessage就是建房子的動做,name是書,protoype屬性是地址。構造函數就是每放一本書就要建一個房子,而原型就是經過地址去尋找房子。
//建房子
function Person(){
}
//房子裏有什麼並肯定了指針的指向
Person.prototype={
name:"tan",
age:"22",
showMessage:function(){
alert("name:"+this.name);
}
};
var person1 = new Person();
person1這樣就有了指針,就能訪問指針指向的內存空間。
我想大家應該有如下的疑問:
1)對象person1是否能夠有本身的屬性?
能夠有,並且對於person1和原型Person中都有的屬性,先考慮的是person1中的屬性。
2)是否能經過person1改變原型屬性值:
對不起,不能夠,實例person1只是獲取了一個指向原型的指針,他並無改變原型的權利。但有一點要特別注意,對於包含引用類型的屬性——列如數組。有一些操做是容許經過地址去訪問內存的,列如push,這些操做就有可能改變原型屬性,這個改變會形成災難性的後果,由於全部引用這個原型的對象都會隨之改變。
四、組合使用構造函數和原型來創造對象(自定義類型,也叫引用類型)
這是經常使用的自定義類型的建立方式,構造函數用來定義實例屬性,而原型用於定義方法和共享屬性。所以,每個實例都會有本身的一份實例屬性的副本,但同時又共享着對方法的引用,最大限度的節約了內存。例如:
function Person(name,age){
this.name=name;
this.age=age;
}
//房子裏有什麼並肯定了指針的指向
Person.prototype={
construction:Person,
showMessage:function(){
alert("name:"+this.name);
}
};
var person1 = newPerson("tan",22);
prototype中的默認的construction屬性,讓原型指向構造函數,默認是Person。
五、原型鏈與繼承
咱們以上說的都是同類型下的對象,person1和person2都是Person的實例。假如我有Person和Man兩個引用類型,Person中的屬性和方法是有Man須要的,我想偷懶直接從
Person中全部的屬性和方法拿過來,這就是繼承。那麼我做爲一個繼承的引用類型我能得到誰的屬性和方法,那麼在這個問題上就會有原型鏈的概念。當對象嘗試獲某個屬性時,該對象沒有,會嘗試從原型對象中去找,原型對象沒有,在從原型對象的原型去找,最後到達Object.prototype。
例如:
function Person(name,age){
this.pname=name;
this.page=age;
}
Person.prototype={
showPMessage:function(){
alert("name:"+this.pname);
}
};
function Man(name,age){
this.mname=name;
this.mage=age;
}
//這一句話表示原型的指針指向了Person
Man.prototype = new Person("tan",22,"man");
//給原型添加方法必定要放在替換原型的語句以後
Man.prototype.test="wosi";
Man.prototype.showMMessage=function(){
alert("name:"+this.mname);
};
var song=new Man("song",1);
song.showMMessage();//顯示song
song.showPMessage();//顯示tan
出處:https://blog.csdn.net/tanzhengyu/article/details/50888657