javascript必知必會之prototype

來源:互聯網
上載者:User

javascript 是一種 prototype based programming 的語言, 而與我們通常的 class based programming 有很大 的區別,我列舉重要的幾點如下:

  1. 函數是first class object, 也就是說函數與對象具有相同的語言地位
  2. 沒有類,只有對象
  3. 函數也是一種對象,所謂的函數對象
  4. 對象是按 引用 來傳遞的

那麼這種 prototype based programming 的語言如何?繼承呢(OO的一大基本要素), 這也便是 prototype 的由來.

看下面的代碼片斷:

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(方法或者屬性).

下面我們主要看下prototype.

// prototypefunction 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.prototype.agealert(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);alert(fun.school);//輸出的是 "undefined"alert(Person.whoAreYou()); //輸出 zhutaoalert(fun.whoAreYou()); // I'm Tower and I'm a male.}Person.prototype.getSalary = function(){return "I can earn 1000000 USD";};if (flag){alert(fun.getSalary());//已經繼承了改變, 即所謂的 動態}

既然有函數對象本身的屬性, 也有prototype的屬性, 那麼是由其建立的對象是如何搜尋相應的屬性的呢?

基本是按照下面的流程和順序來進行.

  1. 先去搜尋函數對象本身的屬性,如果找到立即執行
  2. 如果1沒有找到,則會去搜尋prototype屬性,有2種結果,找到則直接執行,否則繼續搜尋 父物件 的 父物件 的prototype, 直至找到,或者到達 prototype chain 的結尾(結尾會是Object對象)

上面也回答如果函數對象本身的屬性與prototype屬性相同(重名)時的解決方式, 函數本身的對象 優先 .

再看一個多重prototype鏈的例子:

// 多重prototype鏈的例子function Employee(name){this.name = "";this.dept = "general";this.gender = "unknown";}function WorkerBee(){this.projects = [];this.hasCar = false;}WorkerBee.prototype = new Employee; // 第一層prototype鏈function Engineer(){this.dept = "engineer"; //覆蓋了 "父物件"this.language = "javascript";}Engineer.prototype = new WorkerBee; // 第二層prototype鏈var jay = new Engineer("Jay");if (flag){alert(jay.dept);    //engineer, 找到的是自己的屬性alert(jay.hasCar);  // false, 搜尋到的是自己上一層的屬性alert(jay.gender);  // unknown, 搜尋到的是自己上二層的屬性}

上面這個樣本的對象關係如下:

結論

javascript 的prototype給語言本身增加了很強的靈活性,但與 class based programming 相比整個思維邏輯還是有很大的不同,所以需要更多地思考和揣摩.

而 javascript是披著c語言外衣的函數式語言 的理解自然也需要更多地思考.

下一節我會繼續討論下 javascript 的另一個重要而且比較容易弄錯的知識 closure.

歡迎大家留言討論.

參考資料
  1. json
  2. class based programming
  3. prototype based programming
  4. Using Prototype Property in JavaScript
本文的rst源碼

本文的源碼連結在 這裡 .

本文中涉及的javascript代碼可以在 這兒 下載.

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.