1. <i id="s6b2k"><small id="s6b2k"></small></i>
    <b id="s6b2k"><bdo id="s6b2k"></bdo></b>
  2. <wbr id="s6b2k"></wbr>

    帶你徹底理解JavaScript中的原型對象_JavaScript

    來源:腳本之家  責任編輯:小易  

    一、什么是原型

    原型是Javascript中的繼承的基礎,JavaScript的繼承就是基于原型的繼承。

    1.1 函數的原型對象

    ​ 在JavaScript中,我們創建一個函數A(就是聲明一個函數), 那么瀏覽器就會在內存中創建一個對象B,而且每個函數都默認會有一個屬性 prototype 指向了這個對象( 即:prototype的屬性的值是這個對象 )。這個對象B就是函數A的原型對象,簡稱函數的原型。這個原型對象B 默認會有一個屬性 constructor 指向了這個函數A ( 意思就是說:constructor屬性的值是函數A )。

    ​ 看下面的代碼:

    <body>
        <script type="text/javascript">
        	/*
        		聲明一個函數,則這個函數默認會有一個屬性叫 prototype 。而且瀏覽器會自動按照一定的規則
        		創建一個對象,這個對象就是這個函數的原型對象,prototype屬性指向這個原型對象。這個原型對象
        		有一個屬性叫constructor 執行了這個函數
    			
    			注意:原型對象默認只有屬性:constructor。其他都是從Object繼承而來,暫且不用考慮。
    		*/
    	    function Person () {
    	    	
    	    }	    
        </script>
    </body>
    

    下面的圖描述了聲明一個函數之后發生的事情:

    1.2 使用構造函數創建對象

    ​ 當把一個函數作為構造函數 (理論上任何函數都可以作為構造函數) 使用new創建對象的時候,那么這個對象就會存在一個默認的不可見的屬性,來指向了構造函數的原型對象。 這個不可見的屬性我們一般用 [[prototype]] 來表示,只是這個屬性沒有辦法直接訪問到。

    ​ 看下面的代碼:

    <body>
        <script type="text/javascript">
    	    function Person () {
    	    	
    	    }	
            /*
            	利用構造函數創建一個對象,則這個對象會自動添加一個不可見的屬性 [[prototype]], 而且這個屬性
            	指向了構造函數的原型對象。
            */
          	var p1 = new Person();
        </script>
    </body>
    

    觀察下面的示意圖:

    說明:

    1.從上面的圖示中可以看到,創建p1對象雖然使用的是Person構造函數,但是對象創建出來之后,這個p1對象其實已經與Person構造函數沒有任何關系了,p1對象的[[ prototype ]]屬性指向的是Person構造函數的原型對象。

    2.如果使用new Person()創建多個對象,則多個對象都會同時指向Person構造函數的原型對象。

    3.我們可以手動給這個原型對象添加屬性和方法,那么p1,p2,p3…這些對象就會共享這些在原型中添加的屬性和方法。

    4.如果我們訪問p1中的一個屬性name,如果在p1對象中找到,則直接返回。如果p1對象中沒有找到,則直接去p1對象的[[prototype]]屬性指向的原型對象中查找,如果查找到則返回。(如果原型中也沒有找到,則繼續向上找原型的原型—原型鏈。 后面再講)。

    5.如果通過p1對象添加了一個屬性name,則p1對象來說就屏蔽了原型中的屬性name。 換句話說:在p1中就沒有辦法訪問到原型的屬性name了。

    6.通過p1對象只能讀取原型中的屬性name的值,而不能修改原型中的屬性name的值。 p1.name = “李四”; 并不是修改了原型中的值,而是在p1對象中給添加了一個屬性name。

    看下面的代碼:

    <body>
        <script type="text/javascript">
    	    function Person () {    	
    	    }
          	// 可以使用Person.prototype 直接訪問到原型對象
    	    //給Person函數的原型對象中添加一個屬性 name并且值是 "張三"
    	    Person.prototype.name = "張三";
    	    Person.prototype.age = 20;
    
    	   	var p1 = new Person();
    	   	/*
    	   		訪問p1對象的屬性name,雖然在p1對象中我們并沒有明確的添加屬性name,但是
    	   		p1的 [[prototype]] 屬性指向的原型中有name屬性,所以這個地方可以訪問到屬性name
    	   		就值。
    	   		注意:這個時候不能通過p1對象刪除name屬性,因為只能刪除在p1中刪除的對象。
    	   	*/
    	   	alert(p1.name);  // 張三
    
    	   	var p2 = new Person();
    	   	alert(p2.name);  // 張三  都是從原型中找到的,所以一樣。
    
    	   	alert(p1.name === p2.name);  // true
    
    	   	// 由于不能修改原型中的值,則這種方法就直接在p1中添加了一個新的屬性name,然后在p1中無法再訪問到
    	   	//原型中的屬性。
    	   	p1.name = "李四";
    	   	alert("p1:" + p1.name);
    	   	// 由于p2中沒有name屬性,則對p2來說仍然是訪問的原型中的屬性。	
    	   	alert("p2:" + p2.name);  // 張三  
        </script>
    </body>
    

    二、與原型有關的幾個屬性和方法

    2.1 prototype屬性

    ​ prototype 存在于構造函數中 (其實任意函數中都有,只是不是構造函數的時候prototype我們不關注而已) ,他指向了這個構造函數的原型對象。

    ​ 參考前面的示意圖。

    2.2 constructor屬性

    ​ constructor屬性存在于原型對象中,他指向了構造函數

    看下面的代碼:

    <script type="text/javascript">
    	function Person () {
    	}
    	alert(Person.prototype.constructor === Person);	// true
    	var p1 = new Person();
      	//使用instanceof 操作符可以判斷一個對象的類型。  
      	//typeof一般用來獲取簡單類型和函數。而引用類型一般使用instanceof,因為引用類型用typeof 總是返回object。
    	alert(p1 instanceof Person);	// true
    </script>
    

    我們根據需要,可以Person.prototype 屬性指定新的對象,來作為Person的原型對象。

    但是這個時候有個問題,新的對象的constructor屬性則不再指向Person構造函數了。

    看下面的代碼:

    <script type="text/javascript">
    	function Person () {
    		
    	}
    	//直接給Person的原型指定對象字面量。則這個對象的constructor屬性不再指向Person函數
    	Person.prototype = {
    		name:"志玲",
    		age:20
    	};
    	var p1 = new Person();
    	alert(p1.name);  // 志玲
    
    	alert(p1 instanceof Person); // true
    	alert(Person.prototype.constructor === Person); //false
      	//如果constructor對你很重要,你應該在Person.prototype中添加一行這樣的代碼:
      	/*
      	Person.prototype = {
          	constructor : Person	//讓constructor重新指向Person函數
      	}
      	*/
    </script>
    

    2.3 __proto__ 屬性(注意:左右各是2個下劃線)

    ​ 用構造方法創建一個新的對象之后,這個對象中默認會有一個不可訪問的屬性 [[prototype]] , 這個屬性就指向了構造方法的原型對象。

    ​ 但是在個別瀏覽器中,也提供了對這個屬性[[prototype]]的訪問(chrome瀏覽器和火狐瀏覽器。ie瀏覽器不支持)。訪問方式:p1.__proto__

    ​ 但是開發者盡量不要用這種方式去訪問,因為操作不慎會改變這個對象的繼承原型鏈。

    <script type="text/javascript">
    	function Person () {
    		
    	}
    	//直接給Person的原型指定對象字面量。則這個對象的constructor屬性不再指向Person函數
    	Person.prototype = {
    		constructor : Person,
    		name:"志玲",
    		age:20
    	};
    	var p1 = new Person();
    
    	alert(p1.__proto__ === Person.prototype);	//true
    	
    </script>
    

    2.4 hasOwnProperty() 方法

    ​ 大家知道,我們用去訪問一個對象的屬性的時候,這個屬性既有可能來自對象本身,也有可能來自這個對象的[[prototype]]屬性指向的原型。

    ​ 那么如何判斷這個對象的來源呢?

    ​ hasOwnProperty方法,可以判斷一個屬性是否來自對象本身。

    <script type="text/javascript">
    	function Person () {
    		
    	}
    	Person.prototype.name = "志玲";
    	var p1 = new Person();
    	p1.sex = "女";
      	//sex屬性是直接在p1屬性中添加,所以是true
    	alert("sex屬性是對象本身的:" + p1.hasOwnProperty("sex"));
      	// name屬性是在原型中添加的,所以是false
    	alert("name屬性是對象本身的:" + p1.hasOwnProperty("name"));
      	//  age 屬性不存在,所以也是false
    	alert("age屬性是存在于對象本身:" + p1.hasOwnProperty("age"));
    	
    </script>
    

    所以,通過hasOwnProperty這個方法可以判斷一個對象是否在對象本身添加的,但是不能判斷是否存在于原型中,因為有可能這個屬性不存在。

    也即是說,在原型中的屬性和不存在的屬性都會返回fasle。

    如何判斷一個屬性是否存在于原型中呢?

    2.5 in 操作符

    ​ in操作符用來判斷一個屬性是否存在于這個對象中。但是在查找這個屬性時候,現在對象本身中找,如果對象找不到再去原型中找。換句話說,只要對象和原型中有一個地方存在這個屬性,就返回true

    <script type="text/javascript">
    	function Person () {
    		
    	}
    	Person.prototype.name = "志玲";
    	var p1 = new Person();
    	p1.sex = "女";
    	alert("sex" in p1);		// 對象本身添加的,所以true
    	alert("name" in p1);	//原型中存在,所以true
    	alert("age" in p1); 	//對象和原型中都不存在,所以false
    	
    </script>
    

    回到前面的問題,如果判斷一個屬性是否存在于原型中:

    如果一個屬性存在,但是沒有在對象本身中,則一定存在于原型中。

    <script type="text/javascript">
    	function Person () {
    	}
    	Person.prototype.name = "志玲";
    	var p1 = new Person();
    	p1.sex = "女";
    	
    	//定義一個函數去判斷原型所在的位置
    	function propertyLocation(obj, prop){
    		if(!(prop in obj)){
    			alert(prop + "屬性不存在");
    		}else if(obj.hasOwnProperty(prop)){
    			alert(prop + "屬性存在于對象中");
    		}else {
    			alert(prop + "對象存在于原型中");
    		}
    	}
    	propertyLocation(p1, "age");
    	propertyLocation(p1, "name");
    	propertyLocation(p1, "sex");
    </script
    

    三、組合原型模型和構造函數模型創建對象

    3.1 原型模型創建對象的缺陷

    ​ 原型中的所有的屬性都是共享的。也就是說,用同一個構造函數創建的對象去訪問原型中的屬性的時候,大家都是訪問的同一個對象,如果一個對象對原型的屬性進行了修改,則會反映到所有的對象上面。

    ​ 但是在實際使用中,每個對象的屬性一般是不同的。張三的姓名是張三,李四的姓名是李四。

    ​ **但是,這個共享特性對 方法(屬性值是函數的屬性)又是非常合適的。**所有的對象共享方法是最佳狀態。這種特性在c#和Java中是天生存在的。

    3.2 構造函數模型創建對象的缺陷

    ​ 在構造函數中添加的屬性和方法,每個對象都有自己獨有的一份,大家不會共享。這個特性對屬性比較合適,但是對方法又不太合適。因為對所有對象來說,他們的方法應該是一份就夠了,沒有必要每人一份,造成內存的浪費和性能的低下。

    <script type="text/javascript">
    	function Person() {
    	    this.name = "李四";
    	    this.age = 20;
    	    this.eat = function() {
    	        alert("吃完東西");
    	    }
    	}
    	var p1 = new Person();
    	var p2 = new Person();
    	//每個對象都會有不同的方法
    	alert(p1.eat === p2.eat); //fasle
    </script>
    

    可以使用下面的方法解決:

    <script type="text/javascript">
    	function Person() {
    	    this.name = "李四";
    	    this.age = 20;
    	    this.eat = eat;
    	}
      	function eat() {
    	    alert("吃完東西");
        }
    	var p1 = new Person();
    	var p2 = new Person();
    	//因為eat屬性都是賦值的同一個函數,所以是true
    	alert(p1.eat === p2.eat); //true
    </script>
    

    但是上面的這種解決方法具有致命的缺陷:封裝性太差。使用面向對象,目的之一就是封裝代碼,這個時候為了性能又要把代碼抽出對象之外,這是反人類的設計。

    3.3 使用組合模式解決上述兩種缺陷

    ​ 原型模式適合封裝方法,構造函數模式適合封裝屬性,綜合兩種模式的優點就有了組合模式。

    <script type="text/javascript">
    	//在構造方法內部封裝屬性
    	function Person(name, age) {
    	    this.name = name;
    	    this.age = age;
    	}
    	//在原型對象內封裝方法
    	Person.prototype.eat = function (food) {
    		alert(this.name + "愛吃" + food);
    	}
    	Person.prototype.play = function (playName) {
    		alert(this.name + "愛玩" + playName);
    	}
        
    	var p1 = new Person("李四", 20);
    	var p2 = new Person("張三", 30);
    	p1.eat("蘋果");
    	p2.eat("香蕉");
    	p1.play("志玲");
    	p2.play("鳳姐");
    </script>
    

    四、動態原型模式創建對象

    ​ 前面講到的組合模式,也并非完美無缺,有一點也是感覺不是很完美。把構造方法和原型分開寫,總讓人感覺不舒服,應該想辦法把構造方法和原型封裝在一起,所以就有了動態原型模式。

    ​ 動態原型模式把所有的屬性和方法都封裝在構造方法中,而僅僅在需要的時候才去在構造方法中初始化原型,又保持了同時使用構造函數和原型的優點。

    看下面的代碼:

    <script type="text/javascript">
    	//構造方法內部封裝屬性
    	function Person(name, age) {
    		//每個對象都添加自己的屬性
    	    this.name = name;
    	    this.age = age;
    	    /*
    	    	判斷this.eat這個屬性是不是function,如果不是function則證明是第一次創建對象,
    	    	則把這個funcion添加到原型中。
    	    	如果是function,則代表原型中已經有了這個方法,則不需要再添加。
    	    	perfect!完美解決了性能和代碼的封裝問題。
    	    */
    	    if(typeof this.eat !== "function"){
    	    	Person.prototype.eat = function () {
    	    		alert(this.name + " 在吃");
    	    	}
    	    }
    	}
    	var p1 = new Person("志玲", 40);
    	p1.eat();	
    </script>
    

    到此這篇關于帶你徹底理解JavaScript中的原型對象的文章就介紹到這了,更多相關理解js原型對象內容請搜索真格學網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持真格學網!

    您可能感興趣的文章:全面解析js中的原型,原型對象,原型鏈一文秒懂JavaScript構造函數、實例、原型對象以及原型鏈詳解js中的原型,原型對象,原型鏈JS原型對象操作實例分析JavaScript原型對象原理與應用分析JavaScript原型對象、構造函數和實例對象功能與用法詳解

  3. 本文相關:
  4. 微信小程序 教程之wxss
  5. 微信小程序 實戰程序簡易新聞的制作
  6. 微信小程序(十五)checkbox組件詳細介紹
  7. 顏色選擇: colormatch 5k
  8. 微信小程序 http請求詳細介紹
  9. 微信小程序中用webstorm使用less
  10. 基于javascript獲取base64圖片大小
  11. 微信小程序 video詳解及簡單實例
  12. php:微信小程序 微信支付服務端集成實例詳解及源碼下載
  13. 微信小程序 wx.request(接口調用方式)詳解及實例
  14. 如何理解javascript中,原型也是一個對象?
  15. 求解釋javascript的類、對象、方法、原型對象的意...
  16. 深入理解Javascript中構造函數和原型對象的區別
  17. 如何通俗解釋 JavaScript 中的原型概念
  18. javascript原型對象的問題?
  19. JavaScript中什么是原型對象,個人表示不理解。回...
  20. 如何理解javascript原型鏈
  21. javascript對象方法的原型是對象自己?
  22. 怎么理解javascript原型鏈
  23. 如何理解Javascript中類和對象這兩個概念
  24. 網站首頁網頁制作腳本下載服務器操作系統網站運營平面設計媒體動畫電腦基礎硬件教程網絡安全javascriptasp.netphp編程ajax相關正則表達式asp編程jsp編程編程10000問css/htmlflex腳本加解密web2.0xml/rss網頁編輯器相關技巧安全相關網頁播放器其它綜合dart首頁全面解析js中的原型,原型對象,原型鏈一文秒懂javascript構造函數、實例、原型對象以及原型鏈詳解js中的原型,原型對象,原型鏈js原型對象操作實例分析javascript原型對象原理與應用分析javascript原型對象、構造函數和實例對象功能與用法詳解微信小程序 教程之wxss微信小程序 實戰程序簡易新聞的制作微信小程序(十五)checkbox組件詳細介紹顏色選擇: colormatch 5k微信小程序 http請求詳細介紹微信小程序中用webstorm使用less基于javascript獲取base64圖片大小微信小程序 video詳解及簡單實例php:微信小程序 微信支付服務端集成實例詳解及源碼下載微信小程序 wx.request(接口調用方式)詳解及實例微信小程序 數組(增,刪,改,查微信小程序 for 循環詳解微信小程序 input輸入框控件詳解微信小程序 input輸入框詳解及簡微信小程序 小程序制作及動畫(a微信小程序 傳值取值的幾種方法總微信小程序中使元素占滿整個屏幕微信小程序 wx.request(接口調用微信小程序 時間格式化(util.fo微信小程序通過api接口將json數據微信小程序 動態傳參實例詳解微信小程序 繪圖之餅圖實現js、html代碼運行工具微信小程序開發之相冊選擇和拍照詳解及實微信小程序 后臺https域名綁定和免費的ht微信小程序getphonenumber獲取用戶手機號微信小程序圖片選擇、上傳到服務器、預覽微信小程序 form組件詳解及簡單實例用move.js配合創建css3動畫的入門指引微信小程序 向左滑動刪除功能的實現
    免責聲明 - 關于我們 - 聯系我們 - 廣告聯系 - 友情鏈接 - 幫助中心 - 頻道導航
    Copyright © 2017 www.yu113.com All Rights Reserved
    战天txt全集下载