上一篇講了js的prototype概念,在這裏回顧一下prototype的定義:數組
prototype是函數的一個屬性,而且是函數的原型對象。引用它的必然是函數,這個應該記住。dom
可是,很奇怪,各位看官,你有沒有看過相似下面這樣引用prototype的js代碼:函數
function func(){ var args = Array.prototype.slice.call(arguments, 1); return args; }
咦???看着上面這行代碼,你是否是對prototype只是屬於函數產生深深的懷疑呢?this
你明白上面那個函數的意思嗎?我仍是解釋一下吧。spa
call是函數的一個方法,關於這個方法,它也是隻有····函數····纔可以調用的,它的做用是:調用引用它的函數。prototype
就拿這個Array.prototype.slice.call(arguments,1)來說,這裏麪包含太多信息了,我一個個分析一下。code
slice(start[,end])是js的一個原生數組函數,做用是獲取數組中從start下標開始到end下標結束的元素。舉個例子:對象
var arr1 = [2,3,'l',4,5,'j','i']; alert(arr1.slice(1));//結束下標省略表示從開始下標截取到末尾
//這裏alert的是3,'l',4,5,'j','i',你本身能夠試一下
arguments是js函數對象的一個屬性,做用是獲取函數的實參,返回的是一個以函數實參爲屬性元素的對象。舉個例子:blog
function args(){ return this.arguments;//這裏的this能夠省略,你本身能夠試一下
//我加上是爲了說明,調用arguments的只能是對象
} alert(JSON.stringify(args(1,3,5,6,8))); //返回的是{"0":"1","1":"3","2":"5","3":"6","4":"8"}
關於函數的對象屬性arguments這裏就講這麼多了,要詳細理解,能夠百度。繼承
而Array是js中生成數組的關鍵字。
這裏爲何要用Array.prototype來調用slice函數呢?而不用Array.slice,緣由很簡單,由於數組的關鍵字Array不能這樣子Array.xx直接調用js的數組函數。但爲何不能直接這樣調用呢?不急,下面咱們來作實驗,你就會很清楚了。
alert(Array.slice()); //Uncaught TypeError: Array.slice is not a function
這裏直接給你報錯了,說明了什麼?呵呵,這說明Array關鍵字確實不能直接調用數組的函數。
alert(JSON.stringify(Array.prototype));
alert(JSON.stringify(Array.prototype.slice()));
這裏返回都是空數組···[]···,說明了什麼?說明了Array關鍵字確實是能夠調用prototype函數的屬性的,同時也說明js是能夠這樣子Array.prototype調用js的數組函數的。
說到這裏,問題就來了,我上面不是說,prototype是js函數的一個屬性,只能被函數調用嗎?怎麼這裏Array關鍵字能夠調用這個屬性prototype呢?那麼,我這不是坑本身對prototype的定義是錯誤的嗎?我這不是給本身打臉嗎?哎,看官,沒錯,你這裏看到的都是正確的。但是,至於Array關鍵字能夠調用函數的prototype屬性,我有沒有給本身打臉,這裏,咱們先別急得下結論。
轉個彎說,看官是否還記得js生成數組的幾種方式?應該有多種,但,我這裏就不介紹了。
不過,你是否看過這樣生成數組的方式?咱們先來看下面的代碼:
var arr = new Array();
這個方式生成數組還記得吧?那麼,咱們js的function是否是也能夠像下面這樣子生成對象呢?
function func(){ } var obj = new func();
上面生成數組的方式和下面構造函數生成對象的方式是否是很類似?沒錯,js中function和Array都是能夠經過new來生成對象這樣的東西,這說明了什麼呢?你看Array()和func()是否是很像?是否是最後面都有一對圓括號?是就對了,呵呵,說了這麼多,我只是想揭露同樣東西,這個東西就是,假如我猜的的沒有錯的話,Array()這個東西實際上是js一個·····構造數組的內置函數····,否則,能夠用new Array()的方式生存數組的方式就說不過去了是吧?
講到這裏,咱們再返回來講js能夠這樣子Array.prototype調用prototype就很明白不過了是吧?Array()是js的一個內置函數,既然Array是一個函數,那麼Array確定擁有prototype這個屬性對吧?因此說,Array關鍵字調用prototype並無違反prototype是函數的一個屬性這個原則,prototype是函數的一個屬性依然是一個不變的結論。
關於Array生成數組的方式,相似的咱們是否能夠這樣子new Object()生成對象,或者new String()這樣子生成字符串?既然能夠這樣子構造對象和字符串,那麼咱們下面的代碼也應該是可行的,對吧?
alert(JSON.stringify(String.prototype));
alert(JSON.stringify(Object.prototype));
根據上面的解釋,你應該知道這裏是能夠執行的吧?你應該知道這裏的之因此能執行的原理吧?你本身試試。這裏就再也不解釋了。
講到這裏,哎,我既然把行文開始的那個函數給忘了?這裏講解一下本文開始那個func函數的做用:
func函數的做用就是,從第二個實參數開始獲取func函數的實參。
我來給你分析一下:
function func(){ var args = Array.prototype.slice.call(arguments, 1); return args; } alert(func(0,1,2,3,4));//給func函數傳實參
Array.prototype是一個空數組,
Array.prototype.slice()的意思是一個空數組調用數組的函數slice(),
Array.prototype.slice.call()的意思是call函數調用數組的函數slice(),
這裏call()怎麼調用slice()呢?
是這樣子的,Arguments獲取func函數實參列表,生成一個對象傳遞給call()函數,call函數又把Arguments生成的對象傳遞給Array.prototype這個空數組,把第二個參數···1···傳遞給slice函數,而後,call就讓引用它的函數slice執行slice(1),因此slice就從1下標開始獲取數組的元素了,而這個數組的元素其實就是Arguments的元素,所以,這個函數func的做用就是獲取下標爲1開始的全部實參。不相信,你本身能夠執行一下上面的函數。
下面講講prototype的應用:
應用1:
給原型對象增長函數,就是讓對象擁有公用的函數。
例子:我給數組原型對象增長一個打亂數組方法:
//給數組原型增長一個打亂數組的函數 Array.prototype.shuffle=function(){ var value = this.valueOf(),len = this.length,temp,key; while(len--){ //隨機生成數組的下標 key = Math.floor(Math.random()*len); //temp爲中間交換變量 temp = value[key]; value[key] = value[len]; value[len] = temp; } return value; } var arr1 = [0,1,2,3,4,5,6,7,8,9]; var arr2 = ['a','b','c','d','e','f']; alert(JSON.stringify(arr1.shuffle())); alert(JSON.stringify(arr2.shuffle()));
你能夠嘗試着再增長一個數組arr3看看它能不能調用shuffle函數,由於我這裏是給Array的原型對象增長的函數,因此在這個腳本內,全部數組都擁有shuffle這個函數。
應用2:
給原型對象增長屬性,也就是給對象增長公用的屬性
例子:
function fun(){ } fun.prototype.name = '小東'; fun.prototype.arr = [1,2,3,4];//這裏的屬性能夠是數組,也能夠是對象 var ob1 = new fun(); var ob2 = new fun(); alert(JSON.stringify(ob1.name)); alert(JSON.stringify(ob2.arr));
應用3:
實現原型繼承;
function P1(){ } function P2(){ } //原型對象增長屬性和方法 P2.prototype.name = 'P2"s name'; P2.prototype.get=function(value){ return value; } //實例化P2構造函數的一個對象 var obp2 = new P2();//這個對象應該包含全部原型對象的屬性和方法 //給P1的原型對象賦值一個對象,至關於P1繼承了obp2的全部屬性和方法 P1.prototype = obp2;//這個式子,簡單來說就相似於a = b, b賦值給a這個總該明白吧? //調用P1從obp2繼承過來的get函數 alert(P1.prototype.get('out"s name')); //展現P1從obp2繼承過來的name屬性 alert(P1.prototype.name); //用構造函數P1實例化一個obp1對象 var obp1 = new P1(); //P1的原型對象prototype既然已經繼承了obp2的全部屬性和函數,那麼依據P1所實例化出來的對象也都有obp2的屬性和函數了 alert(obp1.get('obp1"s name'));
關於prototype就講到這裏,假如本文有什麼錯誤,還望各位看官指出,我好糾正。
特別指出:
Array.prototype是一個數組
String.prototype是一個字符串
Object.prototype是一個對象