面向對象這個概念並不陌生,如 C++、Java 都是面嚮對象語言。面向對象而言都會現有一個類的概念 ,先有類再有對象。類是實例的類型模板。javascript
好比人類 是一個類 張三 李四 就是一個個對象,他們都是人類建立出的對象 因此都有人類的共同特性,好比 人類都會吃飯 人類都會走路 因此張三李四也會吃飯和走路。java
JavaScript 沒有類的概念,是基於原型的面向對象方式。它們的區別在於:編程
在基於類的面向對象方式中,對象(object)依靠類(class)來產生。 在基於原型的面向對象方式中,對象(object)則是依靠構造函數(constructor)和原型(prototype)構造出來的。
面嚮對象語言的第一個特性毫無疑問是封裝,在 JS 中,封裝的過程就是把一些 屬性 和 方法 放到對象中「包裹」起來。segmentfault
1) 字面量的方式設計模式
示例
函數
var per = { name: "張三", age: 20, sex: "男", say: function () { console.log("說話"); } };
2) Object實例添加屬性方法學習
示例
this
var per2=new Object(); per2.name="李四"; per2.age=30; per2.sex="男"; per2.say=function () { console.log("說話"); };
優勢:代碼簡單。prototype
缺點: 建立多個對象會產生大量的代碼,編寫麻煩,且並無實例與原型的概念。設計
解決辦法:工廠模式。
概念
工廠模式是很是常見的一種設計模式,它抽象了建立具體對象的過程。JS 中建立一個函數,把建立新對象、添加對象屬性、返回對象的過程放到這個函數中,
用戶只需調用函數來生成對象而無需關注對象建立細節。
示例
function createObject(name,age) { this.name=name; this.age=age; this.say=function () { console.log("說話"); }; } var per1=createObject("張三",20); var per2=createObject("李四",30);
優勢:工廠模式解決了對象字面量建立對象代碼重複問題,建立類似對象可使用同一API。
缺點:由於是調用函建立對象,沒法識別對象的類型。
解決辦法:構造函數
JS 中構造函數與其餘函數的惟一區別,就在於調用它的方式不一樣。任何函數,只要經過new
操做符來調用,那它就能夠做爲構造函數。
示例
//自定義構造函數----->實例化對象 function Person(name,age,sex) { this.name=name; this.age=age; this.sex=sex; this.say=function () { console.log("說話"); }; } //構造函數---->建立對象 var per1=new Person("張三",20,"女"); var per2=new Person("李四",30,"女");
經過構造函數new
一個實例經歷了四步:
1. 建立一個新對象; 2. 將構造函數內的 this 綁定到新對象上; 3. 爲新對象添加屬性和方法; 4. 返回新對象(JS 引擎會默認添加 return this;)。
而經過構造函數建立的對象都有一個constructor
屬性,它是一個指向構造函數自己的指針,所以就能夠檢測對象的類型。
alert(per1.constructor === Person) //true alert(per1 instanceof Person) // true
可是仍然存在問題:
alert(per1.say == per2.say) //false
同一個構造函數中定義了say()
,而不一樣對象的同名函數倒是不相等的,意味着這兩個同名函數的內存空間不一致,也就是構造函數中的方法要在每一個實例上從新建立一次。
這顯然增長沒必要要內存空間。
優勢:解決了相似對象建立問題,且能夠檢測對象類型。
缺點:構造函數方法要在每一個實例上新建一次。
解決辦法:原型模式。
在JS中,建立對象的方式有工廠模式和構造函數模式等; 而構造函數模式最大的問題在於:構造函數中的每一個方法都須要在實例對象中從新建立一遍,不能複用
,
因此爲了解決這一個問題,就須要使用原型模式來建立對象。原型模式是把全部實例共享的方法和屬性放在一個叫作 prototype(原型)
的屬性中 ,在建立一個函數
時都會有個prototype屬性, 這個屬性是一個指針,指向一個對象,是經過調用構造函數而建立的那個對象實例的原型對象。
若是你學習過java,咱們能夠簡單理解原型就比如咱們的靜態方法,任何對象均可以共享這個靜態方法。
做用
共享數據,節省內存空間。
使用原型,就意味着咱們能夠把但願實例共享的屬性和方法放到原型對象中去,而不是放在構造函數中,這樣每一次經過構造函數new
一個實例,原型對象中定義
的方法都不會從新建立一次。
示例
//原型的做用之一:共享數據,節省內存空間 function Person() { } //經過構造函數的原型添加屬性和方法 Person.prototype.name = "張三"; Person.prototype.age = "20"; Person.prototype.say = function() { alert('經過原型建立吃飯方法'); }; var person1 = new Person(); var person2 = new Person(); alert(person1.name); //"張三" alert(person2.name); //"張三" alert(person1.say == person2.say); //true 經過原型建立的方法就爲true
優勢:與單純使用構造函數不同,原型對象中的方法不會在實例中從新建立一次,節約內存。
缺點:使用空構造函數,實例 person1 和 person2 的 name
都同樣了,咱們顯然不但願全部實例屬性方法都同樣,它們仍是要有本身獨有的屬性方法。
而且若是原型中對象中有引用類型值,實例中得到的都是該值的引用,意味着一個實例修改了這個值,其餘實例中的值都會相應改變。
解決辦法:構造函數+原型模式組合使用。
最後一種方式就是組合使用構造函數和原型模式,構造函數用於定義實例屬性,而共享屬性和方法定義在原型對象中。這樣每一個實例都有本身獨有的屬性,
同時又有對共享方法的引用,節省內存。
//原型的做用之一:共享數據,節省內存空間 //構造函數 function Person(age,sex) { this.age=age; this.sex=sex; } //經過構造函數的原型添加一個方法 Person.prototype.eat=function () { console.log("經過原型建立吃飯方法"); }; var per1=new Person(20,"男"); var per2=new Person(20,"女"); alert(per1.eat == per2.eat); //經過原型建立的方法就爲true
這種構造函數與原型模式混成的模式,是目前在 JS 中使用最爲普遍的一種建立對象的方法。
一、JS面向對象編程之封裝 基本上參考這篇寫的,由於我認爲它寫的很是通俗易懂,不須要我再去整理了。很是感謝
二、js面向對象編程
別人罵我胖,我會生氣,由於我內心認可了我胖。別人說我矮,我就會以爲可笑,由於我內心知道我不可能矮。這就是咱們爲何會對別人的攻擊生氣。 攻我盾者,乃我心裏之矛(2)。