- 函數是first class object,也就是說函數與對象具備相同的語言地位
- 沒有類,只有對象
- 函數也是一種對象,所謂的函數對象
- 對象是按引用來傳遞的
那麼這種 prototype based programming 的語言如何實現繼承呢(OO的一大基本要素), 這也即是 prototype 的由來。java
看下面的代碼片段:web
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);
對於上面的代碼,用瀏覽器運行後你會發現:編程
- length: 提供的是函數的參數個數
- prototype: 是一個object
- 其它三個都是function
而對於任何一個函數的聲明,它都將會具備上面所述的5個property(方法或者屬性)。瀏覽器
下面咱們主要看下prototype。app
// prototype 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.prototype.age alert(Person.prototype.age); }
從上面的示例中咱們能夠發現,對於prototype的方法或者屬性,咱們能夠動態地增長, 而由其建立的對象自動會繼承相關的方法和屬性。ide
另外,每一個對象都有一個 constructor 屬性,用於指向建立其的函數對象,如上例中的 fun.constructor 指向的就是 Person。函數
那麼一個疑問就天然產生了, 函數對象中自身聲明的方法和屬性與prototype聲明的對象有什麼差異?post
有下面幾個差異:this
- 自身聲明的方法和屬性是靜態的,也就是說你在聲明後,試圖再去增長新的方法或者修改已有的方法,並不會對由其建立的對象產生影響,也即繼承失敗。
- 而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()); //輸出 zhutao alert(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沒有找到,則會去搜索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, 搜索到的是本身上二層的屬性 }
上面這個示例的對象關係以下:
![](http://static.javashuo.com/static/loading.gif)
javascript 的prototype給語言自己增長了很強的靈活性,但與 class based programming 相比整個思惟邏輯仍是有很大的不一樣,因此須要更多地思考和揣摩。
而javascript是披着c語言外衣的函數式語言的理解天然也須要更多地思考。
window.onload = function() { /* 每一個對象實例都有個屬性成員用於指向到它的instanceof 對象(暫稱爲父對象)的原型(prototype) 咱們把這種層層指向父原型的關係稱爲[原型鏈 prototype chian] 原型也具備父原型,由於它每每也是一個對象實例,除非咱們人爲地去改變它 在JavaScript中,"一切都是對象,函數是第一型。" Function和Object都是函數的實例。 Function的父原型指向到Function的原型,Function.prototype的父原型是Object的原型 Object的父原型也指向到Function的原型,Object.prototype是全部父原型的頂層 在spiderMonkey引擎中,父原型能夠經過 __proto__ 進行訪問 你們在看的時候最後能反覆的讀幾篇,能加深理解,尤爲是原型,父原型,還有原型鏈的意思. * prototype 訪問的是原型 * __proto__ 訪問的父原型 * instanceof 原型鏈的父類 */ Function.prototype.hi = function(){alert('hi Function');} Object.prototype.hi = function(){alert('hi Object');} var a = function() { this.txt = 'a'; }; a.prototype = { say:function(){alert('a');} }; alert(a instanceof Function);//a是Function的實例; alert(a.__proto__ === Function.prototype); //a的父原型指向到Function的原型; //a.__proto__父原型 Function //Function.prototype 父原型 Function alert(Function instanceof Object); //Function是Object的實例; alert(Function.__proto__ === Function.prototype); //Function的父原型指向到Function的原型; alert(Function.prototype.__proto__ === Object.prototype); //Function的原型的父原型指向到Object的原型 alert(Object.__proto__ === Function.prototype); //Object的父原型指向到Function的原型; alert(Object.prototype.__proto__); //Object的原型是全部父原型的頂端,它再也不具備父原型,因此結果爲null; alert(a.prototype instanceof Object); //a的原型也是一個對象 alert(a.prototype.__proto__ === Object.prototype); //a的原型的父原型指向Object的原型 };
轉載隨意,但請帶上本文地址: