面向對象的基礎
1.聲明一個對象
var myperson={
name : "Zhang",
age : 25,
sex : "male",
introduction:function(){
alert(name+age+sex);
}
};
myperson.introduction();
2.使用構造函數構造
構造函數與普通函數的區別在於調用方式,構造函數使用new方法構造。
function creatrPerson(name,age,sex,interests){
this.name = name;
this.age = age;
this.sex = sex;
this.interests = interests;
this.bio = function(){
var res = "";
if(this.sex == "male"){
res+="He ";
}else if(this.sex=="female"){
res+="She ";
}else{
res+="It "
}
for(var i=0;i<interests.length;i++){
res+="likes "+interests[i];
if(i!=interests.length-1){
res+=" and ";
}
}
alert(res);
}
}
var zhang = new creatrPerson("zhang",18,"male",["basekatball","swiming","singing"]);
zhang.bio();
3.使用Object 構造
首先創建了一個空對象,之後使用點或括號表示法向此對象添加屬性和方法
var person1 = new Object();
person1.name = 'Chris';
person1['age'] = 38;
person1.greeting = function() {
alert('Hi! I\'m ' + this.name + '.');
}
對象原型
原型基礎
JavaScript 常被描述爲一種基於原型的語言 (prototype-based language)——每個對象擁有一個原型對象。
注意:與Java的面向對象設計不同,java中存在類的概念,創建對象後,會將類的屬性和方法複製到對象中。
而JS中,會通過_proto_屬性來建立構造方法與對象實例的連接。
原型鏈
每個 function方法中都具有 prototype 屬性,其對應的也就是我們通過 function 構造出實例的 proto 屬性。接下來舉個例子。
function doSomething(){}
doSomething.prototype.foo = "bar"; // add a property onto the prototype
var doSomeInstancing = new doSomething();
doSomeInstancing.prop = "some value"; // add a property onto the object
console.log( doSomeInstancing );
對應輸出如下,可以看到實例對象的_proto_對應構造函數的 protoype(因爲設置了foo這個屬性)。同時注意一點,JS會在需要某個對象的屬性時,會首先去尋找該對象是否存在該屬性,之後會去對象的_proto_屬性中尋找,依次類推,如果找不到則會判斷該屬性爲Undefined,這條鏈路被稱爲原型鏈。
doSomeInstacing對象 的 proto 屬性對應的的就是 dosomething構造函數 的 prototype 屬性
{
prop: "some value",
__proto__: {
foo: "bar",
constructor: ƒ doSomething(),
__proto__: {
constructor: ƒ Object(),
hasOwnProperty: ƒ hasOwnProperty(),
isPrototypeOf: ƒ isPrototypeOf(),
propertyIsEnumerable: ƒ propertyIsEnumerable(),
toLocaleString: ƒ toLocaleString(),
toString: ƒ toString(),
valueOf: ƒ valueOf()
}
}
}
我們可以進一步理解原型鏈。我們使用之前cteatePerson
方法去構造一個對象 Zhang。可以看到 Zhang 對象有多個屬性或方法供我們使用。
- 瀏覽器首先檢查,Zhang 對象是否具有 valueOf() 方法。
- 如果沒有,則瀏覽器檢查 Zhang 對象的原型對象(_proto_屬性)是否 valueof() 方法。
- 如果沒有,則會進而調用 createPerson 構造函數的 prototype 對象,去 Object 構造函數中尋找是否具有 valueOf() 方法。這裏有這個方法,於是該方法被調用。
原型鏈的訪問順序:Zhang->createPerson->Object
修改原型
1.prototype 屬性
繼承的屬性和方法都在prototype中定義。這也就是爲什麼上文訪問 Zhang.valueOf 能返回具體的值,因爲Object.prototype.valueOf 可以供任何繼承自它的對象使用。
而任何不在 prototype 中的屬性或方法僅能供 Object 自己使用,繼承自它的對象無法使用。
2.constructor 屬性
每個實例對象都從原型對象那裏繼承了一個構造器,下述代碼都會返回 CreatePerson()構造器。
person1.constructor
person2.constructor
我們同樣可以使用構造器來構造對象。
person3 = new person1.constructor("feng",20,"male",["hha","aaa"]);
3.修改原型
我們嘗試修改(添加)構造器中的prototype
屬性。
creatrPerson.prototype.farewell = function() {
alert(this.name + ' has left the building. Bye for now!');
}
之後調用對象實例的 farewell
方法。瀏覽器會通過原型鏈找到構造器的prototype
對象,並調用farewell
方法
zhang.farewell()
值得注意的是,我們首先創建的的對象實例,之後才爲構造器添加屬性(方法),對象實例仍然能通過原型鏈找到該方法。
證明了下游對象(Zhang)在創建時不是複製了上游對象(構造函數的prototype)的方法和屬性,而是建立了聯繫。在訪問下游對象未定義的方法時,下游對象可以通過原型鏈訪問到上游對象中的對應方法。
繼承
可以通過上述文章瞭解,JS的繼承和Java不同,是通過原型鏈來完成的。因此我們接着嘗試創建繼承自另一個對象的的JS對象。