面向對象是很多高級程序程序設計語言的核心。面向對象的標志就是類、對象、繼承、派生等。js嚴格意義上來講并不是面向對象的語言,因為它沒有類這個概念(即便es6出現了class關鍵字)。但是js可以用自己的方式來模擬面向對象。
<br>
###何謂對象
在js中對象就是一組無序屬性的集合,一個對象可以含有任何類型的屬性和方法,每一個屬性和方法都有一個自己的名字,通過"."或者"[ ]"來調用。
<br>
###一、創建一個對象
####1. 使用Object類型創建
js的一大好處就是可以動態去添加屬性和方法
~~~
var people = new Object();
people.name = "SunnyChuan";//添加一個屬性
people.age = 22;
people.getAge = function() {//添加一個方法
return this.name;
}
~~~
####2. 使用字面量方式
~~~
var people = {
name : "SunnyChuan";
age : 22;
getAge : function() {
return this.name;
}
}
~~~
當然,你也可以這樣創建一個對象
~~~
var people = {};
people.name = "SunnyChuan";
people.age = 22;
people.getAge = function() {
return this.name;
}
~~~
<br>
###二、更優雅地創建對象
使用Object構造函數和字面量可以很輕松地創建對象,但是這兩種方法都有一個致命的缺點———代碼冗余,如果單單創建一個簡單的對象使用這兩種方式沒有任何問題,但是如果我要創建一百個學生對象呢?
這時候就出現了很多"高級"的方式來創建對象。
####1. 工廠模式
顧名思義,這種方式就像工廠一樣,提供了底層的對象模板,在產生新的對象時只需要根據需求在這個模板里添加值即可。
~~~
function createPeople(name, age) {
var obj = new Object();
obj.name = name;
obj.age = age;
obj.getAge = function() {
return this.age;
}
}
var people = createPeople("SunnyChuan",22);
console.log(people.name);
console.log(people.age);
~~~
####2. 構造函數
支持面向對象的高級程序設計語言都支持構造函數模式,在創建對象的時候為這個對象初始化成員變量和成員方法,js模擬了這一功能。
~~~
function People(name, age) {
this.name = name;
this.age = age;
this.getAge = function() {
return this.age;
}//不需要返回
}
var people = new People("SunnyChuan",22);//注意和工廠模式的區別
~~~
和工廠模式不同,構造函數內部并不是顯示地創建對象所以不需要返回,這也就意味著在創建對象時需要new。
####3. 原型模式
要說js里面最神奇的東西無外乎是原型。什么是原型?我理解為一個對象的本來面目,可以把它理解成對象的財產。這個原型屬性其實是一個指針,這個指針指向所有該對象的實例。實例共享原型的屬性和方法。
~~~
function People() {
People.prototype.name = "SunnyChuan";
People.protptype.age = 22;
People.prototype.getAge = function() {
return this.age;
}
}
var people1 = new People(),people2 = new People();
console.log(people1.name + " " + people1.age);
console.log(people2.name + " " + people2.age);
~~~
上述代碼運行的結果是什么?你也許會因為控制臺的兩條完全一致的信息而困惑,這是因為原型模式為People對象添加了原型,這個原型上有name、age屬性和getAge方法。這些東西都是被實例共享的。
來看一段有意思的代碼
~~~
var people = new People();
console.log(people.name);//SunnyChuan
people.name = "DannyQin";
console.log(people.name);//DannyQin
delete people.name;
console.log(people.name);//SunnyChuan
~~~
原型允許我添加一個自己獨有的屬性去覆蓋原型的屬性,一旦添加,原型的同名屬性就會被覆蓋掉,直到這個獨有的屬性被刪除,原型的屬性又會暴露出來。這就好比我和一個朋友共有一本書,但是我嫌這本書太舊,于是我就自己買了一本一模一樣的新書。直到有一天我新買的書丟了,我又迫不得已去和朋友一起使用那本舊書了。
ps:這里有一個坑,當我修改原型后實例也會動態去更改,但是如果重寫原型,那么已經創建的實例不會受到影響。
####4. 組合構造函數和原型模式
原型很強大,但是缺點也很明顯:屬性共享,我相信在實際開發過程中沒有哪一個對象的所有實例的名字都叫"SunnyChuan",這時候一個真正強大的模式就產生了。組合模式使用構造函數定義屬性,使用原型定義方法。
~~~
function People(name, age) {
this.name = name;
this.age = age;
}
People.prototype.getAge = function() {
return this.age;
}//如果方法比較多也可以使用字面量的形式
var people1 = new People("SunnyChuan",22);
var people2 = new People("DannyQin",21);
console.log(people1.name + " "+ people2.name);
~~~
5. 還有很多模式,諸如動態原型模式、寄生構造函數模式等等
<br>
###三、繼承
有類就會有繼承,就像有父親必有兒子一樣。js既然可以模擬類,那么同樣可以模擬繼承。
####1. 原型鏈
什么是原型鏈?原型鏈的基本思想是利用原型讓一個引用類型繼承另一個引用類型的屬性和方法,讓原型對象等于另一個類型的實例,上述關系層層遞進形成原型鏈。簡單來說就是一個引用類型a是另一個引用類型b的原型,而b又是c的原型,這樣就構成了a到b到c的一條原型鏈。在查找屬性時通過原型鏈一層層地向上查找該屬性,如果找到了則返回。舉個不恰當的例子,假如兒子欠了一筆錢,如果兒子沒錢債主就會向他的老爸要錢,如果老爸也沒有,那就向他的爺爺要錢,一直向上追債直到把錢要回來。
~~~
function Father() {
this.name = "SunnyChuan";
}
Father.prototype.getName = function() {
return this.name;
}
function Son() {
this.name = "DannyQin";//覆蓋父類的name
}
Son.prototype = new Father();//父類作為子類的原型
var s = new Son();//也可以重寫父類的方法
console.log(s.getName());//DannyQin
~~~
子類重寫父類的方法時,由于方法是使用原型實現,所以如果使用字面量的形式重寫會破壞整個繼承關系(因為會重寫整個原型,導致子類的原型不再是父類)。
####2. 借用構造函數
構造函數模式通過給this的屬性賦值來達到創建對象的目的,那么如果通過改變this的指向是不是就可以實現繼承了?答案是肯定的,那么什么方法可以改變this的指向呢?
~~~
function Father(name) {
this.name = name;
}
function Son(name, age) {
Father.call(this, name);
this.age = age;
}
var s = new Son("DannyQin",22);
console.log(s.name + " " + s.age);
~~~
####3. 組合繼承
原型鏈模式和構造函數模式繼承都有各自的缺點,與創建對象策略相同,使用組合繼承的方式可以彌補二者的缺點。
~~~
function Father(name) {
this.name = name;
}
Father.prototype.getName = function() {
return this.name;
}
function Son(name, age){
Father.call(this, name);
this.age = age;
}
Son.prototype = new Father();
//可以重寫父類的getName()
Son.prototype.getAge = function() {
return this.age;
}
~~~
<br>
###總結
js的面向對象是一個很復雜而又實用的技術,通過面向對象可以實現類似于私有變量等等模仿類的各種功能,我會繼續挖掘下去。
- html/css
- 不一樣的css3之Transform
- 不一樣的css3之Transition
- 不一樣的css3之Animation
- Less初學
- Sass初學
- 水平垂直居中那些事
- css優先級
- css基礎教學
- javascript
- 淺談javascript事件處理程序
- cookie,localStorage,sessionStorage的區別
- Ajax
- 說說JSON
- 數組常用的方法
- 字符串常用的方法
- 閉包之我的理解
- 常用DOM操作
- 扒一扒所謂的面向對象
- JS Blob對象
- ES6學習筆記(一)
- ES6學習筆記(二)
- 用ES6書寫React
- React+Redux實戰總結
- 基于Express搭建開發環境
- 其他
- github初學
- 輕松配置Webpack
- asp.net學習筆記
- ado.net
- 如何使用ajax進行前后端交互
- 銀行大廳自助服務系統需求分析
- 西電銀行開發手冊
- 接口
- ajax