JavaScript--面向對象

1.建立對象
 1) 工廠模式
  function createPerson(name,age,job){
   var o = new Object();
   o.name = name;
   o.age = age;
   o.job = job;
   o.sayName = function(){
    alert(this.name);
   }
   return o;
  }
  var p1 = createPerson("terry",11,"boss");
  var p2 = createPerson("larry",12,"daBoss");app

  工廠模式的問題
   var t1 = typeOf p1; //object 沒法對象識別,即全部對象都是Object類型
2) 構造函數模式
    js中能夠自定義構造函數,從而自定義對象類型的屬性和方法,構造函數自己也是函數,只不過能夠用來建立對象函數

  function Person(name,age,job){
   this.name = name;
   this.age = age;
   this.job = job;
   this.sayName = function(){
    alert(this.name);
   }
  }
  var p1 = new Person("terry",11,"boss");
  var p2 = new Person("larry",12,"daBoss");
  使用new操做符調用構造函數建立對象實際上經歷了以下幾個步驟
   1) 建立一個新對象
   2) 將構造函數的做用域賦給新對象(this指向這個新對象)
   3) 執行構造函數中的代碼
   4) 返回新對象。
  這種建立對象的方法能夠將實例標識爲一種特定類型(例如Person類型)。
   var t1 = typeOf p1; //t1爲Personthis

  1.構造函數當作函數
    Person("larry",12,"daBoss")
    當在全局做用域中調用一個函數時,this老是指向Global對象(window對象)。
  2.構造函數的問題
   每一個方法都須要在每一個實例上從新建立一遍,可是毫無必要。
   能夠在全局範圍中聲明一個函數,而後將引用傳遞給對象中的函數屬性。可是這樣作會致使全局函數過多,體現不了對象的封裝性
   console.log(p1.sayName == p2.sayName); //falseprototype

3) 原型模式
  每一個函數都有一個屬性:prototype(原型屬性),這個屬性是一個指針,指向一個對象,該對象的用途是包含能夠由特定類型的全部實例共享的屬性和方法。
   function Person(){指針

   }
   Person.prototype.name = "tom";
   Person.prototype.age = 22;
   Person.prototype.job="boss";
   Person.prototype.sayName = function(){
    alert(this.name);
   }
   var p1 = new Person();
   p1.name = "terry";對象

   var p2 = new Person();
   p2.name = "larry"; 
  建立了自定義的構造函數以後,其原型對象默認會取得constructor屬性;當調用構造函數建立一個新實例後,該實例的內部將包含一個指針(內部屬性),指向構造函數的原型對象。(指向的是原型對象而不是構造函數)繼承

  1.屬性的訪問
   每當代碼讀取某個對象的某個屬性時,都會執行一次搜索,目標是具備給定名字的屬性。
   1) 首先從對象實例自己開始查找
   2) 若是不在對象實例中,則繼續搜索指針指向的原型對象。
  2.刪除實例屬性
   當爲對象實例添加一個屬性時,這個屬性就會屏蔽原型對象中保存的同名屬性。經過delete操做符能夠徹底刪除實例屬性。
  3.檢測屬性是否存在於實例中
   hasOwnProperty(p); 判斷p指定的屬性是否存在於實例中,若是存在返回true
   console.log(p1.hasOwnProperty("name")); //false 存在於原型中而不是實例對象中
  4.原型與in操做符
   1) 在for-in 能夠訪問存在於實例中的屬性,以及原型中的屬性
   2) 單獨使用
   a in b;  經過b對象能夠訪問到a屬性的時候返回true,不管該對象在實例中仍是在原型中
   console.log("name" in p1);  //true
   判斷一個屬性是否在原型
    function hasPrototypeProperty(obj,name){
     //不在實例中可是能夠訪問到的屬性屬於原型屬性
     return !obj.hasOwnProperty(name) && (name in obj);
    }
  5.原生對象的原型
   經過原生對象的原型,不只能夠取得全部默認方法的調用,並且能夠定義新方法。能夠向修改自定義對象的原型同樣修改原生對象的原型,能夠隨時添加方法。
   String.prototype.startsWith = function(text){
    return this.indexOf(text) == 0;
   }
   var msg = "Hello world";
   alert(msg.startsWith("Hello")); //true
  6.原型對象的問題 
   全部實例在默認狀況下都將取得相同的屬性值,這種共享對於函數來講很是合適,可是包含引用數據類型的值就不太好
   Person.prototype = {
    name : "briup",
    friends : ["larry","terry"]
   }
   var p1 = new Person();
   var p2 = new Person();
   p1.name = "terry";
   p1.friends.push("tom");ip

   p1.friends; //["larry","terry","tom"]
   p2.friends; //["larry","terry","tom"]原型鏈

  7.更簡單的原型語法
   將原型對象設置爲等於一個對象字面量形式建立的新對象。實例對象使用效果相同,可是原型中的constructor屬性再也不指向Person,由於每建立一個對象,就會同時建立它的 prototype對象,這個對象也自動得到constructor屬性。這裏咱們重寫了prototype對象所以該原型中constructor屬性就變成了新對象的constructor屬性(Object)
   p1.constructor.prototype.constructor //Object
   function Person(){
  
   }
   Person.property = {
    //constructor: Person,   若是constructor比較重要,能夠指定它的值,Enumerable ,true,默認爲false
    name:"tom",
    age :22,
    job :"boss",
    sayName:function(){
     alert(this.name);
    }
   }
   //定義constructor屬性,不可遍歷
   Object.defineProperty(Person.prototype,"constructor",{
    enumerable : false,
    value : Person
   });
 
 4) 組合使用構造函數模式和原型模式
  構造函數用於定義實例屬性,原型模式用於定義方法和共享屬性。這種模式是目前在ECMAScript中使用最普遍,認同度最高的一種建立自定義類型的方法。
   function Person(name,age){
    this.name = name,
    this.age = age,
    this.friends = []
   }
   Person.prototype = {
    constructor : Person,
    sayName:function(){
     alert(this.name);
    }
   }
   var p1 = new Person("terry",11);
   var p2 = new Person("larry",12);
   p1.friends.push("tom");
   p2.friends.push("jacky");
   console.log(p1);
   console.log(p2);作用域

2.繼承
 1) 原型鏈      
   每一個構造函數都有一個原型對象,原型對象中都包含一個指向構造函數的指針,而實例都包含一個指向原型對象的內部指針。當原型對象等於另一個類型的實例即繼承。調用某個方法或者屬性的步驟
     a.搜索實例
     b.搜索原型
     c.搜索父類原型
  //定義父類類型
  function Animal(){
   this.name = "animal" 
  }
  Animal.prototype = {
   sayName : function(){
    alert(this.name);
   }
  }

  //定義子類類型
  function Dog(){
   this.color = "灰色"
  }
  //經過將子對象的原型對象指向父對象的一個實例來完成繼承
  Dog.prototype = new Animal();
  //子對象的方法實際上是定義在了父類對象的實例上。
  Dog.prototype.sayColor = function(){
   alert(this.color);
  }
  var dog = new Dog();
  console.log(dog);
  dog.sayColor();
  dog.sayName();
  1.默認原型
   全部函數默認原型都是Object的實例,默認原型中都會包含一個內部指針,指向Object.prototype.
  2.肯定原型和實例的關係
   1) 經過使用instanceof
    instance instanceof Object //true
    instance instanceof SuperType //true
    instance instanceof SubType //true
   2) 經過使用isPrototypeOf()
    只要是原型鏈中出現過的原型,均可以說是該原型鏈所派生的實例的原型
    Object.prototype.isPrototypeOf(instance) //true
    SuperType.prototype.isPrototypeOf(instance) //true
    SubType.prototype.isPrototypeOf(instance) //true
  3.謹慎定義方法
   子類型覆蓋超類型中的某個方法,或者是須要添加超類中不存在的方法,都須要將給原型添加方法的代碼放在繼承以後(即替換原型的語句以後)
  4.原型鏈問題
   1)經過原型來實現繼承時,原型實際上會變成另外一個類型的實例,原來的實例屬性也就變成了如今的原型屬性
   2)在建立子類型的實例時,不能向超類型的構造函數傳遞參數。
   所以實踐中不多會單獨使用原型鏈

    2) 借用構造函數 
  也稱 "僞造對象" 或 "經典繼承",在子類型構造函數的內部調用超類型構造函數。函數不過是在特定環境中執行代碼的對象,所以經過apply(),call()方法能夠在(未來)新建對象上執行構造函數,即 在子類型對象上執行父類型函數中定義的全部對象初始化的代碼。結果每一個子類實例中都具備了父類型中的屬性以及方法
  function Animal(name){
   this.name = name;
   this.colors = ["red","gray"];
  }
  function Dog(name){
   //繼承了Animal
   Animal.call(this,name);
   this.color = "gray";
  }
  Animal.prototype.sayName = function(){
   alert(this.name);
  }

  var dog = new Dog();
  dog.colors.push("hhh");
  console.log(dog);
  var animal = new Animal();
  console.log(animal);
    //若是將函數定義在構造函數中,函數複用無從談起
  dog.sayName(); 
    //在超類型的原型中定義的方法,對於子類型而言是沒法看到的

    3) 組合函數
  也稱"僞經典繼承",將原型鏈和借用構造函數的技術組合在一塊兒。原理是:使用原型鏈實現對原型屬性和方法的繼承,而經過借用構造函數實現對實例屬性的繼承。
  function Animal(name){
   this.name = name;
   this.colors = ["red","gray"];
  }
  function Dog(name){
   //繼承了Animal(屬性)
   Animal.call(this,name);
   this.color = "gray";
  }
  Animal.prototype.sayName = function(){
   alert(this.name);
  }
  //繼承方法
  Dog.prototype = new Animal();
  Dog.prototype.constructor = Animal;

  var dog = new Dog();  dog.colors.push("hhh");  console.log(dog);  var animal = new Animal();  console.log(animal);  dog.sayName(); //能夠調用

相關文章
相關標籤/搜索