面向對象小記

面向對象、原型

面向對象

想開一個車,你不須要本身去造一個車,只須要一把鑰匙,車對於你來講就是一個"對象"。
在JavaScript中的"對象", 具備屬性,當屬性的值是一個函數時,那麼此屬性就是這個對象的方法.訪問屬性的方式參考Object介紹瀏覽器

如何建立對象?

首先想到的是字面量建立對象,其次是建立一個對象實例,而後一次對對象屬性進行賦值.可是不管這兩種那個方法都有個缺點,當須要重複建立大量相同的對象時,產生大量代碼這是很不理想的,這時想到函數的一個功能就是講重複代碼進行簡化,以便屢次使用,那麼構造函數形式建立多個對象方式就是理想的選擇了.函數

什麼是構造函數?

function outPut() {
    console.log('hello')
}

function Person (name,age) {
    this.name2 = name;
    this.age2 = age;
    this.sayName = function () {
        console.log('this.name2')
    };
}

var person2 = new person("Kangkang" , 20)

// 分別調用

這裏有幾點須要注意,首先是這個this是誰? new操做符有什麼做用?this

  • this指向的建立的實例,這裏指的是 person2, 而new操做符能夠建立一個對象實例.

使用new經過構造函數方式建立對象的實際包含的步驟有:

  1. 建立一個新對象,
  2. 將構造函數的做用域賦給新對象,此時this已經指向新對象,操做this等同操做新對象
  3. 執行構造函數裏的代碼
  4. 返回建立的新對象

如何檢測對象的類型? (檢測操做符右邊的函數原型是否存在於左邊的實例的原型鏈上)

使用instanceof 操做符,返回布爾值.spa

p1 instanceof Person;
p1 instanceof Object;

第二個檢測,不管是本身建立的構造函數對象仍是字面量對象,均爲true,由於他們均繼承自Object. 對於某個構造函數建立的實例當其構造函數的原型被改變後使用此操做符發現返回false ,緣由在於在實例的原型鏈上構造函數的原型是舊的對象,不是新的對象,天然也就不對了。instanceof-MDNprototype

那麼對於構造函數建立的對象裏的方法,每次建立實例時都要從新建立,如何解決?

思路是將這個方法提到實例的外面去,若是是全局對象不就能夠直接調用了嗎?但是全局函數對於封裝來講可沒好處,因此原型模式也就有了用處.code

原型

  • 原型是定義可以被對象實例所使用的屬性和函數的一種方式.原型的屬性會變成實例的屬性.

這段話不容易理解.一點點分析,對象的原型屬性(prototype)指向的是一個對象,對象裏存的屬性和方法在對象實例後(即構造函數方法建立的新對象) 能夠被實例對象訪問使用.對象

function Person() {
  
}
Person.prototype.name = "Kangkang"
Person.prototype.age = 20
Person.prototype.sayName = function () {
  console.log(this.name)
}

var person1 = new Person()
person1.sayName() // "Kangkang"

var person2 = new Person()
person2.sayName() //"Kangkang"

console.log(person1.sayName == person2.sayName) //true

var person3 = new Person() 
person3.name = "Mary"
person3.sayName() //"Mary"

在函數建立的時候,prototype屬性就被建立出來了,經過構造函數生成的實例在瀏覽器下支持一個屬性__proto__ 查看prototype(原型裏的對象)
圖1繼承

如圖所示
顯示的是當一個實例在本身屬性中找不到相應的方法或者屬性時往上一層尋找的狀況。ip

檢測某個屬性屬於實例仍是原型:原型鏈

  1. person1.hasOwnProperty("name") 當這個屬性是實例的返回true,是原型的返回false
  2. 注意到在實例中重寫某個屬性會阻止訪問原型中的這個屬性,但是不會影響到原型中的屬性。

單獨操做的in操做符

  1. 使用這個操做符能夠檢測某個屬性是否能夠經過對象訪問,這也就指的是不管這個屬性是實例中的仍是原型中的,要知道實例能夠經過 __proto__ 訪問,由上圖可知
  2. "name" in Person1 能夠訪問返回true,不然返回false
  3. 這個操做符能夠和上面的hasOwnperty() 結合使用判斷某個屬性是否存在且存在於哪裏。

如何爲原型添加屬性和方法?

由上面介紹可知,經過Person.prototype.name = "kangkang"
這種方法甚是繁瑣,多個屬性、方法將會致使反覆的輸入,因此對象字面量的書寫方式就能很好解決這個問題。

function Person () {
    
} 

Person.prototype = {
    name : "Kangkang",
    age: 20,
    job: 'student',
    sayName = function() {
        console.log(name)
    }
}

防止實例與原型的鏈斷開

謹慎在初始化原型後再將其改變爲另一個對象

function Person () {
    
} 

var friend = new Person()
Person.prototype.sayHi = function() {
    console.log('hi')
}

friend.sayHI();

// 在建立對象後再對原型添加方法依然有效

下面這種狀況:

function Person () {
    
} 

var friend = new Person()

Person.prototype = {
    name : "Kangkang",
    age: 20,
    job: 'student',
    friends: ["xiaojun","xiaoming"],
    sayName : function() {
        console.log(name)
    }
    
friend.sayName();// error

這種狀況至關於在原型初始化後又從新生成對象而且賦值,而原來的實例是指向初始化時的對象地址,故沒法訪問新的原型裏的屬性和方法.

原型對象和屬性的區別?

以下程序:

function Person () {
    
} 

Person.prototype = {
    name : "Kangkang",
    age: 20,
    job: 'student',
    friends: ["xiaojun","xiaoming"],
    sayName : function() {
        console.log(name)
    }
}

var person6 = new Person()
var person7 = new Person()

// person6.name  = "Mary"

// console.log(person6.name)
// console.log(person7.name)

// person6.sayName = function() {
//   console.log('hi')
// }
person6.friends.push('xiaohong')
console.log(person6.friends)
console.log(person7.friends)

console.log(person6.sayName == person7.sayName)

由上面的代碼得出:

當對原型中基本類型值屬性和方法在實例中從新添加會阻止尋找到原型中的屬性和方法,當用delete 操做符刪除後依然能夠找到原型中的屬性和方法,也就是說在實例中重定義這兩種狀況不會影響原型中的屬性和方法,可是若是原型中的屬性對應的值是引用類型,因爲引用類型的特性,實例獲得了相同的這個屬性的地址,又因爲原型是實例公用的方法,因此當任一實例操做這個引用值屬性時都會影響到其餘這個對象的實例。因此組合使用構造函數和原型也就很好解決這個問題。

使用構造函數模式和原型模式組合

function Person (name, age, job) {
  this.name = name
  this.age = age
  this.job = job
  this.friends = ['kangkang','mary']
}
Person.prototype = {
  constructor : Person,
  sayName : function () {
    console.log(this.name)
  }
}

var person1 = new Person('xiaojun',22,'student')
var person2 = new Person('xiaowang', 21, 'student')

person1.friends.push('xiaozhang')

console.log(person1.friends) // ["kangkang", "mary", "xiaozhang"]
console.log(person2.friends) // ["kangkang", "mary"]
console.log(person1.friends === person2.friends) //false
console.log(person1.sayName === person2.sayName) //true

初學筆記,我的記錄備忘,若有謬誤,歡迎指正。

相關文章
相關標籤/搜索