1. 程式人生 > 實用技巧 >javascript學習五---OOP

javascript學習五---OOP

面向物件:JavaScript的所有資料都可以看成物件
JavaScript的面向物件程式設計和大多數其他語言如Java、C#的面向物件程式設計都不太一樣。如果你熟悉Java或C#,很好,你一定明白麵向物件的兩個基本概念:
   面向物件的兩個基本概念:
       1、類:類是物件的型別模板,例如,定義Student類來表示學生,類本身是一種型別,Student表示學生型別,但不表示任何具體的某個學生;
       2、例項:例項是根據類建立的物件,例如,根據Student類可以創建出xiaoming、xiaohong、xiaojun等多個例項,每個例項表示一個具體的學生,他們全都屬於Student型別。
       所以,類和例項是大多數面向物件程式語言的基本概念。

   JavaScript不區分類和例項的概念,而是通過原型(prototype)來實現面向物件程式設計。
   JavaScript的原型鏈和Java的Class區別就在,它沒有“Class”的概念,所有物件都是例項,所謂繼承關係不過是把一個物件的原型指向另一個物件而已。

   JS的prototype和__proto__
一、prototype和__proto__的概念 prototype是函式的一個屬性(每個函式都有一個prototype屬性),這個屬性是一個指標,指向一個物件。它是顯示修改物件的原型的屬性。 __proto__是一個物件擁有的內建屬性(請注意:prototype是函式的內建屬性,__proto__是物件的內建屬性),是JS內部使用尋找原型鏈的屬性 用chrome和FF都可以訪問到物件的__proto__屬性,IE不可以。 二、
new 的過程 var Person = function
(){}; var p = new Person(); new的過程拆分成以下三步: (1) var p={}; 也就是說,初始化一個物件p (2) p.__proto__ = Person.prototype; (3) Person.call(p); 也就是說構造p,也可以稱之為初始化p 關鍵在於第二步,我們來證明一下: var Person = function(){}; var p = new Person(); alert(p.__proto__
=== Person.prototype); 三、示例 var Person = function(){}; Person.prototype.sayName = function() { alert("My Name is Jacky"); }; Person.prototype.age = 27; var p = new Person(); p.sayName(); p是一個引用指向Person的物件。我們在Person的原型上定義了一個sayName方法和age屬性,當我們執行p.age時,會先在this的內部查詢(也就是建構函式內部),如果沒有找到然後再沿著原型鏈向上追溯。 這裡的向上追溯是怎麼向上的呢?這裡就要使用__proto__屬性來連結到原型(也就是Person.prototype)進行查詢。最終在原型上找到了age屬性 為了解決從原型物件生成例項的問題,Javascript提供了一個建構函式(Constructor)模式。 所謂"建構函式",其實就是一個普通函式,但是內部使用了this變數。對建構函式使用new運算子,就能生成例項,並且this變數會繫結在例項物件上。 案例:   function Cat(name,color){     this.name=name;     this.color=color;   } 我們現在就可以生成例項物件了。   var cat1 = new Cat("大毛","黃色");   var cat2 = new Cat("二毛","黑色");   alert(cat1.name); // 大毛   alert(cat1.color); // 黃色 這時cat1和cat2會自動含有一個constructor屬性,指向它們的建構函式。   alert(cat1.constructor == Cat); //true   alert(cat2.constructor == Cat); //true Javascript還提供了一個instanceof運算子,驗證原型物件與例項物件之間的關係。   alert(cat1 instanceof Cat); //true   alert(cat2 instanceof Cat); //true 五、 Prototype模式 Javascript規定,每一個建構函式都有一個prototype屬性,指向另一個物件。這個物件的所有屬性和方法,都會被建構函式的例項繼承。 這意味著,我們可以把那些不變的屬性和方法,直接定義在prototype物件上。 這意味著,我們可以把那些不變的屬性和方法,直接定義在prototype物件上。   function Cat(name,color){     this.name = name;     this.color = color;   }   Cat.prototype.type = "貓科動物";   Cat.prototype.eat = function(){alert("吃老鼠")}; 六、 Prototype模式的驗證方法 6.1 isPrototypeOf() 這個方法用來判斷,某個proptotype物件和某個例項之間的關係。   alert(Cat.prototype.isPrototypeOf(cat1)); //true   alert(Cat.prototype.isPrototypeOf(cat2)); //true 6.2 hasOwnProperty() 每個例項物件都有一個hasOwnProperty()方法,用來判斷某一個屬性到底是本地屬性,還是繼承自prototype物件的屬性。   alert(cat1.hasOwnProperty("name")); // true   alert(cat1.hasOwnProperty("type")); // false 6.3 in運算子 in運算子可以用來判斷,某個例項是否含有某個屬性,不管是不是本地屬性。   alert("name" in cat1); // true   alert("type" in cat1); // true in運算子還可以用來遍歷某個物件的所有屬性。   for(var prop in cat1) { alert("cat1["+prop+"]="+cat1[prop]); } 比如,現在有一個"動物"物件的建構函式。   function Animal(){     this.species = "動物";   } 還有一個"貓"物件的建構函式。   function Cat(name,color){     this.name = name;     this.color = color;   } 怎樣才能使"貓"繼承"動物"呢? 一、 建構函式繫結 第一種方法也是最簡單的方法,使用call或apply方法,將父物件的建構函式繫結在子物件上,即在子物件建構函式中加一行:  function Cat(name,color){     Animal.apply(this, arguments);     this.name = name;     this.color = color;   }   var cat1 = new Cat("大毛","黃色");   alert(cat1.species); // 動物 二、 prototype模式 第二種方法更常見,使用prototype屬性。 如果"貓"的prototype物件,指向一個Animal的例項,那麼所有"貓"的例項,就能繼承Animal了。   Cat.prototype = new Animal();   Cat.prototype.constructor = Cat;   var cat1 = new Cat("大毛","黃色");   alert(cat1.species); // 動物 任何一個prototype物件都有一個constructor屬性,指向它的建構函式。 案例: class Student { constructor(name) { this.name = name; } hello() { console.log('Hello, ' + this.name + '!'); } }; var xiaoming = new Student('小明'); xiaoming.hello(); 結果:Hello, 小明! class PrimaryStudent extends Student { constructor(name, grade) { super(name); // 記得用super呼叫父類的構造方法! this.grade = grade; } myGrade() { alert('I am at grade ' + this.grade); } }; var teddy = new PrimaryStudent('teddy','no.1'); teddy.myGrade(); 結果:'I am at grade no.1'