深入理解js的prototype以及prototype的一些應用

来源:http://www.cnblogs.com/loveyoume/archive/2016/12/06/6139681.html
-Advertisement-
Play Games

上一篇講了js的prototype概念,在這裡回顧一下prototype的定義: prototype是函數的一個屬性,並且是函數的原型對象。引用它的必然是函數,這個應該記住。 但是,很奇怪,各位看官,你有沒有看過類似下麵這樣引用prototype的js代碼: 咦???看著上面這行代碼,你是不是對pr ...


  上一篇講了js的prototype概念,在這裡回顧一下prototype的定義:

  prototype是函數的一個屬性,並且是函數的原型對象。引用它的必然是函數,這個應該記住。

  但是,很奇怪,各位看官,你有沒有看過類似下麵這樣引用prototype的js代碼:

function func(){
    var args = Array.prototype.slice.call(arguments, 1);
    return args;
 }

  咦???看著上面這行代碼,你是不是對prototype只是屬於函數產生深深的懷疑呢?

  你明白上面那個函數的意思嗎?我還是解釋一下吧。

  call是函數的一個方法,關於這個方法,它也是只有····函數····才能夠調用的,它的作用是:調用引用它的函數。

  就拿這個Array.prototype.slice.call(arguments,1)來講,這裡麵包含太多信息了,我一個個分析一下。

  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函數對象的一個屬性,作用是獲取函數的實參,返回的是一個以函數實參為屬性元素的對象。舉個例子:

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是一個對象

  這三個特殊例子,不像構造函數的prototype一樣,當然,假如你真的理解prototype是函數的一個原型對象的話,你應該知道,數組的原型對象應該是一個數組,而不可能是一個對象吧?字元串的原型對象應該是字元串而不可能是對象吧?


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 回到目錄 .Net MVC之所以發展的如些之好,一個很重要原因就是它公開了一組AOP的過濾器,即使用這些過濾器可以方便的攔截controller里的action,並註入我們自己的代碼邏輯,向全局的異常記錄,用戶授權,Url授權,操作行為記錄等,這一大批Lind的基本組件都是實現MVC和API的過濾實 ...
  • 代理模式(Proxy)為其他對象提供一種代理以控制對這個對象的訪問。使用場合,第一,遠程代理,也就是為一個對象在不同的地址空間提供局部代表。這樣可以隱藏一個對象存在於不同地址空間的事實;第二,虛擬代理,是根據需要創建開銷很大的對象。通過它來存在實例化需要很長時間的真實對象;第三,安全代理,用來控制真 ...
  • AccountController .java Java代碼 <!--[if gte vml 1]><v:shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@ ...
  • 單點登錄是我比較喜歡的一個技術解決方案,一方面他能夠提高產品使用的便利性,另一方面他分離了各個應用都需要的登錄服務,對性能以及工作量都有好處。自從上次研究過JWT如何應用於會話管理,加之以前的項目中也一直在使用CAS這個比較流行的單點登錄框架,所以就一直在琢磨如何能夠把JWT跟單點登錄結合起來一起使 ...
  • 單例模式, 顧名思義, 就是共用同一個實體對象. 對於共用, 首先想到的就是static靜態變數, 那麼怎麼使用static去實現單例呢. 一、單線程單例模式 由於這個模式的實現還是比較簡單的, 所以直接上代碼.(不推薦使用此方式) 私有化構造函數之後, 外部就不能通過new A()的方式來實例化A ...
  • 單一職責原則 單一職責原則(Single responsibility principle),就一個類而言,應該只有一個引起它變化的原因。 在實際編程中的體現,比如一個類只是某一個事物相關的集合,一個函數只做一件事情,不要在這個函數中編寫一些不想關的邏輯,這樣可以最大程度的提高程式的可維護性,可復用 ...
  • javaScript和HTML支持的字元集 JavaScript是支持unicode的。 現代的瀏覽器在網頁中都支持ASCII字元集、ISO字元集、數學符號、希臘字母、其他符號。HTML5預設使用UTF-8。讀者可以點擊這兒查看ASCII、unicode和utf-8的關係。 javaScript和H ...
  • 1.在使用HTML5的Canvas元素時,考慮到有些瀏覽器不支持canvas元素,或是不支持HTML5 Canvas API中的某些特性,開發人員最好提供一份替代代碼。 以下代碼展示如何在canvas中指定替代文本,當瀏覽器不支持canvas的時候會顯示這些替代內容: <canvas>Update ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...