菜鳥筆記:Javascript 物件導向

用超級英雄圖解物件導向(疑?

初入前端的菜鳥如我,看完這篇很詳細又實用的 JavaScript 物件導向介紹,希望能有更具體的舉例來理解物件導向程式設計(OOP),因此用比較生活化的敘述和圖像來簡單介紹XD

一、物件

建立一個 Javascript 物件的方式很多種,用大括號 {} 就能夠建立一個物件了,物件裡面可以放入各式各樣的屬性,屬性的值不管是字串或是方法都可以。

為了更好理解,我們把這個物件想像是一個「人」來設定:

var p = {
name: 'Peter Parker',
hello: function () {
return 'Hi, I am ' + p.name + '.'
}
}
p.hello()

簡單來說,上面這段產生了 name 屬性是 Peter Parker 的物件,除此之外,他還具有 hello() 的 function,會跟你打招呼「Hi, I am Peter Parker.」

二、用建構式建立物件

單純建立一個物件不難,但是要快速建立很多物件就要用建構式了。
建構式可以先定義物件的特徵,也就是建立物件的屬性與 function 的藍圖。

function Person(name) {
this.name = name;
this.hello = function() {
return 'Hi, I am ' + this.name + '.';
}
}

就像是先設定出「人」應該要有的屬性,只要帶入不同的屬性值,這個程式就能產生任何人。

要實例化這個建構式,創造出物件,要用 new:
1. new 是一個運算符
2. new 的運作模式:
 第一步、先建立空的物件 
 第二步、將 this 設定為指向新物件
 第三步、叫用建構式時,將引數傳入 this 指向的屬性的值
4. 建構式不需要回傳的動作,this 會自動被回傳到新物件

var p = new Person('Peter Parker')
var b = new Person('Bruce Wayne')
p
> p {name: 'Peter Parker', hello: function}
p.hello()
> 'Hi, I am Peter Parker.'
b
> b {name: 'Bruce Wayne', hello: function}
b.hello()
> 'Hi, I am Bruce Wayne.'

變數 p 設為 name 是 Peter Parker 的人,b 則設為 name 是 Bruce Wayne 的人,建構式裡面的 this.say() 也提供了這些建立出來的 Person 物件都具有 hello 的 function,因此,執行各自的 hello() 後,他們都會跟你打招呼。

function Person(name, age, gender, weight, height) {
this.name = name;
this.age = age;
this.gender = gender;
this.weight = weight;
this.height = height;
}

建構式就跟一般物件一樣,可以定義各式各樣的屬性,因此要快速建立數個多屬性物件,就可以用這樣的建構式完成,只要寫一次建構式,剩下的就只要把變數與引數帶入,就能夠大量建立物件。

可以把身為人應該有的屬性都放進去這隻建構式。

三、用 prototype 擴充

除了可以直接把 function,寫在物件屬性裡面,也可以透過 prototype 的方式擴充,這麼做的好處可以讓建構式變得更有彈性,code 更有條理,管理性也更好。

function Person(name, wear) {
this.name = name;
this.wear = wear;
this.fly = false;
}
Person.prototype.inIronSuit = function() {
this.wear = 'ironSuit';
this.fly = true;
}

可以看到 Person 的 fly 值為 false,表示「人」本來不會飛。
另外,用 prototype 擴充了一個穿鋼鐵衣的動作,穿上鋼鐵衣就可以飛啦!

var t = new Person('Tony Stark', 'Suit')
var r = new Person('James Rhodes', 'Suit')

透過上面的建構式,創造出 Tony Stark 和 James Rhodes 兩個人,可以看到他們一開始只是穿著普通的西裝。

t
> t {name: 'Tony Stark', wear: 'Suit', fly: false}
t.inIronSuit() //穿上鋼鐵衣
t
> t {name: 'Tony Stark', wear: 'Iron Suit', fly: true}
// 同理,其他人也可以穿鋼鐵衣
r.inIronSuit()
r
> r {name: 'James Rhodes', wear: 'Iron Suit', fly: true}

在 inIronSuit() 執行後,觀察Tony 和 Rhodes 前後的變化,他們的 wear 屬性都被換成了 ‘Iron Suit’,並且更改了 fly 的值為 true,如此一來他們兩個都能夠在天空飛啦!

補充說明:

擴充方法 (method) 的方式有兩種:
1.this.property = function() {}
2.prototype 
寫出來的效果相同,但是其實背後原理卻是不一樣的。

function A() {
this.a = function() {}
}
A.prototype.b = function() {}
var x = new A()
var y = new A()

乍看之下,a() 和 b() 都是屬於 A() 的方法,但是去檢查後會發現:

x.a === y.a
> false
x.b === y.b
> true

會造成這樣差異是因為,this 的運作方式是「複製」,a 和 b 都是源自 A() 的設定被複製、創造出來的,但是創造出物件的時候 a 和 b 都是獨立的存在,所以物件 x 的 a() 是他自己獨有的,和 y 的 a() 是不一樣的東西。
prototype 做的事情是「傳址」,所以 x.b 和 y.b 所指的東西都是指 b() 這個 function。

四、傳遞 this

方法(method)並不一定只屬於特定的建構式使用時,不同的建構式也是有可能會用到相同的方法。

不論是英雄或壞蛋,他們都有各自的名言要說,所以「說」這個動作,就不需要綁在特定建構式的 prototype。

要注意的是,say 這個方法裡面的 this,不會與 Hero 和 BadGuy 的 this 相通,因此,要使用 bind 傳遞 this,直接看看下面的例子:

function Hero(name, sentence) {
this.name = name;
this.sentence = sentence;
this.say = say.bind(this);
}
function BadGuy(name, sentence) {
this.name = name;
this.sentence = sentence;
this.say = say.bind(this);
}
function say() {
return this.name + ' says "' + this.sentence + '".'
}

若沒有 bind 來做傳遞,say 的 this 就只是指「say 這個 function 本身」,say() 並不知道 this.name 是誰的名字,this.sentence 是誰的句子。

var j = new BadGuy('Joker', 'Why so serious?');
var s = new BadGuy('Darth Vader', 'I am your father.');
var h = new Hero('Hulk', 'WAAAAAAAAAA');
var a = new Hero('Captian America', 'I can do this all day.')

傳遞後的 this,就能夠讓物件屬性在各程式之間轉換,這些角色們也能夠順利地說出自己的名言了!

五、透過建構式創造出超級英雄

用以上的物件導向概念,把物件添加屬性與 method 方法,讓物件更加的豐富和完整:

function Person(name) {
this.name = name;
  this.say = function() {
return 'Hi! I am ' + this.name + '.'
}
}
Person.prototype.heroEvent = function() {
if (this.name == 'Peter Parker') {
this.event = spiderBite.bind(this)
return this.name + ' have some story.'
}
else if (this.name == 'Bruce Wayne') {
this.event = parentDied.bind(this)
return this.name + ' have some story.'
}
}
function spiderBite() {
this.superHero = true;
this.ability = 'Spider power';
this.heroName = 'Spider man';
this.color = 'red and blue'
return 'Now, I got a spider power!'
}
function parentDied() {
this.superHero = true;
this.rich = true;
this.ability = 'none';
this.heroName = 'Batman';
return 'I am rich.'
}

來看看這些程式發生了什麼事吧 :P

以上,是以一個初學者的程度理解的物件導向程式設計(OOP),理解其作法後,對於很多程式的閱讀和撰寫都會更順利。

若有任何建議歡迎與我交流XD