Skip to content

Latest commit

 

History

History
169 lines (123 loc) · 3.3 KB

4.1._JS_的物件導向與原型繼承_prototype.md

File metadata and controls

169 lines (123 loc) · 3.3 KB

4.1. JS 的物件導向與原型繼承

關注物件的創造過程,很容易搞混。

繼承

一個物件可以取得或使用另外一個物件的屬性與方法。

classical inheritance 古典繼承

in C#, Java

prototypal inheritance 原型繼承

in JavaScript

prototype

JavaScript 中, 每一個物件(用 obj 表示)都有一個 proto 屬性, proto 它也是一個物件, 代表的就是 obj 的 prototype。

同時因為 proto 也是物件, 它也會有自己的 proto, 這樣一層一層串連下去就稱之為 prototype chain。

obj 可以使用到 proto 的屬性與方法。

// 一開始執行
obj.prop1
// 沒問題,很順利的運作。
//
//
// 但是當我們要執行:
obj.prop2
// js engine 在 obj 中找不到 prop2,
// 便會往第一層 __proto__ 找。
//
// 執行
obj.prop3
// obj 找不到,
// 往第一層 __proto__ 找,找不到,
// 再往第二層 __proto__ 找。

obj 會自動連結 prototype

// 要取用 prop2 時,
// 我們當然也可以寫成
obj.__proto__.prop2
// 但是我們不需要這麼做,
// js engine 會自動往 prototype 尋找屬性與方法。

藉由共用 prototype 達成 inheritance

obj, obj2 皆可以存取到 prop2, prop3。

所有東西若不是純值就是物件

原始型別 (primitive value, primitive data type) 指的是非 object 的型別,並且不具有 methods。 在 JavaScript裡,共有六種原始型別 :

string, number, boolean, null, undefined, symbol (於 ECMAScript 2015 新推出).

大部份的時候,原始型別由程式語言最底層實作。 所有的原始型別都是不可更改的。

包裹物件

reflection and extend

reflection

var person = {
    fiirstName : "default",
    lastName : "default",
    getFullName: function(){
        return this.fistName + " " + this.lastName;
    }
}
var john = {
    firstName : "john",
    LastName : "dave"
};

// don't do this EVER, for demo purposes only!!
john.__proto__ = person;

// for...in... 遍歷整個 object
for(var prop in john){
    console.log(prop + ":" + john[prop]);
}

// results:
//
// firstName:john
// lastName:dave
// getFullName:function(){
//         return this.fistName + " " + this.lastName;
//     }

會 log 出 getFullName, 所以我們可以得知 for in 會遍歷到 prototype 的屬性與方法。

要避免遍歷到 prototype 的話就要使用 hasOwnProperty():

// 將上面的 for in 改寫成
for(var prop in john){
    if(john.hasOwnProperty(prop)){
        console.log(prop + ":" + john[prop]);
    }
}

// results:
//
// firstName:john
// lastName:dave

extend

使用 underscore 中的 extend 方法來說明:

var jane={
    address: "111 Main St.",
};

var jim={
    getFirstName: function(){
        return this.firstName;
    }
};

// 讓 john 接受其他物件的屬性與方法
_.extend(john, jane, jim);
console.log(john);

// result:

和運用 prototype 不同, 屬性與方法是值加在 john 本身上面。