<!DOCTYPE html PUBLIC "-//W3C//DTDXHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>javascript必知會之prototype</title>
<script type="text/javascript" language="javascript">
function foo(a, b, c) {
return a * b * c;
}
alert(foo.length);
alert(typeof foo.constructor);
alert(typeof foo.call);
alert(typeof foo.apply);
alert(typeof foo.prototype);
/*
對於上面的代碼,用瀏覽器運行後你會發現:
1、length提供的是函數的參數個數
2、prototype是一個object
3、其他三個都是function
而對於任何函數的聲明,他都將會具有上面所述的5個property(方法或者屬性)
下面主要看prototy
*/
function Person(name, gender) {
this.name = name;
this.gender = gender;
this.whoAreYou = function() {//這個所謂的closure;內建函式可以訪問外部函數變數
var res = "I'm " + this.name + " and I'm a " + this.gender;
return res;
};
}
//那麼由Person建立的對象便有了下面幾個屬性
Person.prototype.age = 24;
Person.prototype.getAge = function() {
return this.age;
};
flag = true;
if (flag) {
var fun = new Person("Tower", "male");
alert(fun.name);
alert(fun.gender);
alert(fun.whoAreYou());
alert(fun.getAge());
}
Person.prototype.salary = 10000;
Person.prototype.getSalary = function() {
return this.name + "can earn about " + this.salary + " RMB each month.";
};
/*
下面就是最神奇的地方了,我們改變了Person的prototype,而這個改變是在建立fun之後
而這個改變使得fun也具有了相同屬性和方法
繼承的意味即此
*/
if (flag) {
alert(fun.getSalary());
alert(fun.constructor.prototype.age);//而這個相當於你直接調用了Person.protype.age
alert(Person.prototype.age);
}
/*
從上面的樣本中我們可以發現,對於prototype的方法或者屬性,我們可以 動態地 增加,而由其建立的 對象 自動
會 繼承 相關的方法和屬性
另外,每個對象都一個constructor屬性,用於指向建立其函數的對象,如上例中的fun.constructor指向的就是 Person
那麼一個疑問就自然產生了,"函數對象中自身的方法和屬性與prototype聲明的對象有什麼差別?"
有下面幾個差別:
1、自身聲明的方法和屬性是 靜態,也就是說你在聲明後,試圖再去增加新的方法或者修改已有的方法,並不會對由其建立的對象產生影響,也即繼承失敗。
2、而prototype可以動態增加新的方法或者修改已有的方法,從而是動態,一旦父函數對象聲明了相關的prototype屬性,由其建立的對象會自動繼承這些prototype的屬性
繼續上面的例子
*/
flag = true;
//函數內部聲明的方法是靜態,無法傳遞的
Person.school = "ISCAS";
Person.whoAreYou = function() {
return "zhutao";
}; //動態更改聲明期的方法,並不會影響其建立的方法,即所謂的靜態
if (flag) {
alert(Person.school);//輸出"ISCAS"
alert(fun.school);//輸出"undefined"
alert(Person.whoAreYou());//zhutao
alert(fun.whoAreYou());//I'm Tower and I'm a male.
}
Person.prototype.getSalary = function() {
return "I can earn 1000000USD";
};
if (flag) {
alert(fun.getSalary());//已經整合了改變,即所謂的動態
}
/*
既然有函數對象本身的屬性,也有prototype的屬性,那麼是由其建立的對象是如何搜尋相應的屬性呢?
基本是按照下面的流程和順序來經行的。
1、先去搜尋函數對象本身的屬性,若果找到立即執行
2、如果1沒有找到,則會去搜尋prototype屬性,有2中結果,找到的直接執行,負責積雪搜尋父物件的父物件的prototype,知道找到
或者達到prototype chain的結尾(結尾會是objec對象)
上面的也回答如果函數對象本身的屬性與prototype屬性相同(重名)時的解決方式,函數本身的對象優先
再看一個多重prototype鏈的例子
*/
function Employee(neme) {
this.name = "";
this.dept = "general";
this.gender = "unknown";
}
function WorkerBee() {
this.projects = [];
this.hasCar = false;
}
WorkerBee.prototype = new Employee; //第一層prototype鏈
function Engineer() {
this.dept = "enginner"; //覆蓋了“父物件”
this.language = "javascript";
}
Engineer.prototype = new WorkerBee; //第二層prototype鏈
var jay = new Engineer("Jay");
if (flag) {
alert(jay.dept);//engineer,找到的是自己的屬性
alert(jay.hasCar);//flase,搜到的是自己上一層的屬性
alert(jay.gender);//unknown,搜到的是自己上二層的屬性
}
</script>
</head>
<body>
</body>
</html>