javascript--面向對象學習(原型的深刻學習)

前文                                                                                            

新年第一篇,先說句新年一個星期後快樂,而後再開始個人正文。上個一篇主要說了面向對象中,建立對象的三種模式,工廠模式、構造函數模式還有原型模式,其中比較重要的是原型模式。原型模式中起做用的是原型對象,此次就對原型進行一番深刻的學習。數組

 

內容                                                                                             函數

1、in操做符學習

首先咱們來了解一下in操做符。經過in操做符可以訪問到一個對象中的屬性。也就是說,咱們能夠用過in操做符來查看到底這個對象中是否是有這個屬性,以及肯定這個屬性是來自實例仍是原型。this

講一下in操做符的兩種使用方法spa

1. 單獨使用:經過對象能訪問到屬性是就會返回true,不論是在對象的實力上仍是在原型上。prototype

function Person(){}

		Person.prototype.name = 'jiang';
		Person.prototype.age = 19;
		Person.prototype.job = 'sf';
		Person.prototype.sayName = function(){
			console.log(this.name);
		}

		var p1 = new Person();

		'name' in p1;//true

 經過in操做符檢測到的name屬性,返回值爲true,這說明在p1的實例中能夠檢測到name屬性,可是咱們初始化時並無給實例一個name屬性,說明這個屬性是來自與原型對象的。指針

p1.name='z';
'name' in p1;//true

  當咱們給實例添加一個name屬性的時候,此時依舊仍是true。可是這個很明顯就知道這是來自實例中的屬性。這兩個例子說明,單單只是經過in操做符是沒法知道咱們要檢測的屬性究竟是來自原型對象仍是實例自己。code

p1.hasOwnProperty('name');//true

delete p1.name;
p1.hasOwnProperty('name');//false 

經過調用hasOwnProperty()方法能夠知道這個屬性有沒有存在在實例自己,可是沒法知道這個屬性有沒有存在在原型中。所以能夠經過將這兩種方法封裝一塊兒就能夠知道究竟是來自原型仍是實例。對象

function hasPrototypeProperty(obj, name){
			return !obj.hasOwnProperty(name) && name in obj;
		}

var p2 = new Person();
		hasPrototypeProperty(p2, 'name');//false
		p2.name = 'z';
		hasPrototypeProperty(p2, 'name');//true

只要當hasOwnProperty()返回false,那麼就能夠肯定這個屬性是來自原型,若是返回true就來自對象的實例。blog

2.for-in:返回的是可經過對象訪問到的、可枚舉的屬性,包括原型和實例中的屬性。屏蔽了原型中不可枚舉屬性的實例屬性也能夠在for-in循環中返回,全部開發人員自定義的屬性都是可枚舉的。

var o = {
			toString : function(){
				return "myObject";
			}
		}

		for(var prop in o){
			if(prop == 'toString'){
				console.log(prop);//在ie中不會顯示
			}
		}

注意:ie早期版本存在一個bug,即屏蔽不可枚舉屬性的實例屬性不會在for-in循環中

3.Object.keys()方法。經過調用這個方法,能夠返回對象中包含的全部可枚舉屬性的字符串數組

返回了全部原型對象中可枚舉屬性字符串
var keys = Object.keys(Person.prototype); console.log(key);//name, age, job, sayName 返回了實例中的可枚舉屬性 var key = Object.keys(p1); console.log(key);//name 這裏瞭解一下getOwnPropertyNames()方法 var keys1 = Object.getOwnPropertyNames(Person.prototype); console.log(key);//constructor,name, age, job, sayName //這個方法連不可枚舉屬性constructor也顯示出來了

2、原型的動態性

動態性就是說,咱們在原型對象上的修改,均可以當即在實例中反映出來,即便是先建立了對象的實例再修改。

function Person(){}
        Person.prototype.name = 'jiang';
        Person.prototype.age = 15;
        Person.prototype.job = 'sf';
        Person.prototype.sayName = function(){
            console.log(this.name);
        };


        var person = new Person();
        Person.prototype.sayHi = function(){
            console.log("hi");
        };//向原型中添加一個函數
        person.sayHi();
        

在上面的例子中,咱們先是在個Person對象的原型上添加了屬性和方法,並進行了實例化,而後咱們對Person,prototype進行了修改,添加了一個名爲sayHi的方法。咱們在後面經過實例始終仍是可以訪問到這個方法,這是因爲原型和實例之間的鬆散關係。可是若是咱們用另一種更簡單的原型語法來重構這個對象,那效果就會不同了。

var friend = new Person();
		Person.prototype = {
			name: 'jiang',
			age: 14,
			job: 'sf',
			sayName: function(){
				console.log(this.name);
			}
		}

  這種簡單的原型語法也就是經過字面量的語法來重構,這樣子至關於從新定義了一個新對象,經過重構後,會切斷原型與對象之間的聯繫,原型鏈斷開,原型中的constructor指針不會再指向Person,而是指向了Object。在以前也有說過,當咱們聲明一個函數時,prototype對象會同時被建立,而這個對象也會自動得到constructor屬性,並指向原來的函數,經過上面的方式無異於切斷了二者之間的聯繫。可是咱們能夠經過在對象中添加constructor:Person,來從新得到鏈接。可是若是咱們調用了friend.sayName(),就會報錯,這是由於friend中最初的[[prototype]]已經再也不是指向原來的原型對象了。

修改前:

修改後:

 

 儘管重修原型對象切換了現有的原型與已經建立的實例之間的關係,可是引用的依舊是最初的原型。

3、原生對象的原型

原生對象有哪些:Object、String、Array等等都是原生對象,這些原生的引用類型都是採用原型模式,在其構造函數的原型上定義了方法,好比Array.prototype能夠找到sort()方法。經過原生對象的原型,不只僅能夠獲取默認方法的引用,也能夠在其原型上定義方法。可是最好就不要這麼作。

4、原型對象的問題

並非說原型就是完美的,問題一:忽略參數傳遞初始化參數這一塊,結果全部的實例在默認狀況下取得的值是相同的。問題二:共享性帶來的問題,也是最大的問題。

function Person(){}
		Person.prototype ={
			name : 'jiang',
			aga : 14,
			job : 'sf',
			friend : ['s', 'f'],
			sayName : function(){
				console.log(this.name);
			}
		}

		var p1 = new Person();
		var p2 = new Person();

		p1.friend.push('v');

		console.log(p1.friend);//"s","f","v"
		console.log(p2.friend);//"s","f","v"

  由實例p1中沒有friend這個屬性,因此搜索到原型中有同名屬性,因此在p1中添加的值實質上是添加到了原型的屬性中,而實例p2一樣沒有這個屬性,因此p1的修改影響到了p2。這固然是咱們不肯意看到的,固然共享函數咱們是願意的,而共享屬性的話那麼就問題就大了去,就比如每一個人都有本身隱私,可是由於共享的問題,個人隱私被侵犯了,不就像是被偷窺了同樣嚴重。

夜深人靜了,是時候要就寢了,今晚的內容就這樣吧。晚安~

相關文章
相關標籤/搜索