1. 程式人生 > >構造函數,原型對象,實例對象

構造函數,原型對象,實例對象

解釋 instance img null his 函數的原型 ima var 情況

一、構造函數,原型對象,實例對象

1.1 基本概念

1、對象:

  • 屬性和方法的集合,即變量和函數的封裝。
  • 調用構造函數產生的實例對象, 每個對象都有一個__proto__屬性,指向這個對象的構造函數的原型對象

2、構造器函數:

  • 用於創建對象的函數,通過new關鍵字生成對象。
  • 函數名一般首字母大寫的。
  • 每創建一個函數, 該函數都會自動帶有一個prototype屬性。該屬性是一個指針,指向一個對象,該對象稱之為原型對象(後期我們可以使用這個原型對象幫助我們在js中實現繼承)

3、原型對象:

  • 默認有一個屬性constructor,該屬性也是一個指針,指向其相關聯的構造函數
  • 原型對象其實就是普通對象(但 Function.prototype 除外,它是函數對象,但它很特殊,它沒有prototype屬性(前面說到函數對象都有prototype屬性))
function Person(){};
console.log(Person.prototype) //Person{}

console.log(typeof Person.prototype) //Object
console.log(typeof Function.prototype) // Function,這個特殊
console.log(typeof Object.prototype) // Object
console.log(typeof Function.prototype.prototype) //undefined

1.2 總結

三者的關系是

  • 每個構造函數都有一個指向原型對象的指針,
  • 原型對象上包含著一個指向構造函數的指針,
  • 而實例都包含著一個指向原型對象的內部指針

1.3 舉例

function People(){
    this.type='人'
}
People.prototype.showType=function(){
    alert(this.type);
}

var person=new People();
//調用原型對象上面的方法
person.showType();//最後結果彈框彈出人
  • 構造函數People(), People.prototype指向原型對象,其自帶屬性construtor又指回了People,即People.prototype.constructor==People
    .
  • 實例對象person由於其內部指針__proto__指向了原型對象,所以可以訪問原型對象上的showType方法。

技術分享圖片

person1.__proto__ == Person.prototype

Person.prototype.constructor = Person

person1.constructor == Person

二 原型鏈

舉例1

在第一部分我們說到,所有的實例都有一個內部指針指向他的原型對象,並且可以訪問到原型對象上的所有屬性和方法。

  • person實例對象的__proto__屬性,指向了People的prototype屬性,即原型對象,可以訪問People原型對象上的所有屬性和方法
  • 如果People原型對象變成了某一個類的實例aaa,這個實例又會指向一個新的原型對象AAA,那麽person此時能訪問aaa的實例屬性和AAA原型對象上的所有屬性和方法了。
  • 同理新的原型對象AAA碰巧又是另外一個對象的實例bbb,這個對象實例指向原型對象BBB,那麽person就能訪問bbb的實例屬性和BBB原型上的屬性和方法了。
    技術分享圖片

舉例2

function People(){
    this.type='人'
}
People.prototype.showType=function(){
    alert(this.type);
}

function Woman(){
    this.sex='女';
    this.age=34;
}
Woman.prototype = new People();

var w=new Woman();
console.log('大家好,我的種類是:'+w.type+",我的年齡是:"+w.age+",我的性別是:"+w.sex);
//輸出結果:
//大家好,我的種類是:人,我的年齡是:34,我的性格是:女
//w.type是People上面定義的type

解釋一下以上代碼.

首先先定義了People構造函數,通過new People()得到實例,會包含一個實例對象type和一個原型屬性showType。

另外定義一個Woman構造函數,然後情況發生變化,本來構造函數Woman的prototype會執行Woman的原型對象,但是我們這裏稍有改變,將Woman構造函數的prototype指向了People實例對象覆蓋了Woman的原型對象。

當Woman的實例對象woman去訪問type屬性時,js首先在woman實例屬性中查找,發現沒有定義,接著去Woman的原型對象上找,woman的原型對象這裏已經被我們改成了People實例,那就是去People實例上去找。先找People的實例屬性,發現沒有type,最後去People的原型對象上去找,終於找到了。這個查找就是這麽一級一級的往上查找。

舉例3

function People(){
    this.type='人'
}
People.prototype.showType=function(){
    alert(this.type);
}
function Woman(){
    this.sex='女';
    this.age=34;
    this.type='女生';//如果這裏定義了type屬性,就不會層級查找,最後在People找到該屬性
}
Woman.prototype=new People();
var w=new Woman();
console.log('大家好,我的種類是:'+w.type+",我的年齡是:"+w.age+",我的性別是:"+w.sex);
//輸出結果:
//大家好,我的種類是:女生,我的年齡是:34,我的性格是:女

這就說明,我們可以通過原型鏈的方式,實現 Woman繼承 People 的所有屬性和方法。

總結
就是當重寫了Woman.prototype指向的原型對象後,實例的內部指針也發生了改變,指向了新的原型對象,然後就能實現類與類之間的繼承了

練習

練習1

構造函數Person 實例對象person1

// 題目
1 : person1.__proto__ 是什麽?
2 : Person.__proto__ 是什麽?
3 : Person.prototype.__proto__ 是什麽?
4 : Object.__proto__ 是什麽?
5 : Object.prototype.__proto__ 是什麽?

// 答案
1 : person1.__proto__ === Person.prototype (person1的構造函數Person)

2 : Person.__proto__ === Function.prototpye (Person的構造函數Function)

3 : Person.prototype.__proto__  === Object.prototype (Person.protyotype是一個普通對象,因為一個普通對象的構造函數都是Object)

4 : Object.__proto__ === Function.prototpye (Object的構造函數Function)

5 : Object.prototype.__proto__ === null (Object.prototype 也有__proto__屬性,但是它比較特殊,是null,null處於原型鏈的頂端。)

原型鏈的形成是真正是靠__proto__ 而非prototype

練習2

var FunctionExample = function () {}

Object.prototype.a = function() {}

Function.prototype.b = function() {}

var f = new FunctionExample();

這時候f能否訪問到a和b ??
// 所有普通對象都源於這個Object.prototype對象,只要是對象,都能通過原型鏈訪問到a

f.__proto__ === FunctionExample.prototype;

FunctionExample.prototype.__proto__ === Object.prototype;
// 取b我們可通過 f.constructor.b就能訪問到b,因為 f.constructor == FunctionExample

f.constructor === FunctionExample;

FunctionExample.__proto__ === Function.prototype;
console.log(f) // FunctionExample {}
console.log(f.constructor)  // [Function: FunctionExample]
console.log(FunctionExample.prototype) // FunctionExample {}, 其實可以理解成FunctionExample.prototype就是一個實例
console.log(FunctionExample.prototype.constructor) // [Function: FunctionExample]
console.log(f.__proto__) // FunctionExample {} , 可以這麽理解,實例的proto指向它的構造函數的原型對象,也就是f.__proto__ == FunctionExample.prototype
console.log(f.constructor.b) // Function,因為f.constructor指向 FunctionExample, 而 FunctionExample.prototype相當是Function的一個實例,所以在Function.prototype上有個b函數,FunctionExample照樣可以訪問的到
console.log(f.constructor.prototype.__proto__); // { a: [Function] } 可以訪問到a函數,因為f.constructor.prototype其實就是等於FunctionExample {},而每個對象都有個__proto__屬性,Function.prototype.__proto__ == Object.prototype,所以也能訪問到a方法

練習3

function SuperType() {
  this.colors = ['red', 'yellow']
}

function SubType() {

}
// 繼承了SuperType
SubType.prototype = new SuperType();

var instance1 = new SubType() // intance.constructor = SuperType
instance1.colors.push('black')
console.log(instance1.colors) // ['red', 'yellow', 'black']

var instance2 = new SubType()
console.log(instance2.colors) // ['red', 'yellow', 'black']

理解一下原型和原型鏈

// 為什麽instance1.constructor = SuperType ?
// 為什麽 SubType.prototype.constructor = SuperType ?

console.log(instance1.constructor) // SuperType
console.log(SubType.prototype.constructor) // SuperType

console.log(instance1.__proto__ == SubType.prototype) // true
console.log(SubType.prototype.__proto__ == SuperType.prototype) // true

console.log(SubType.__proto__ == SuperType.prototype) // false
console.log(SubType.__proto__ == Function.prototype) // true

console.log(SuperType.prototype.constructor == SuperType) // true
console.log(SuperType.__proto__ == Function.prototype) // true
console.log(SuperType.prototype.__proto__ == Object.prototype) // true

練習4

function SuperType() {
  this.colors = ['red', 'yellow']
}

function SubType() {
  // 繼承了SuperType
  SuperType.call(this);
}

var instance1 = new SubType()
instance1.colors.push('black')
console.log(instance1.colors) // ['red', 'yellow', 'black']

var instance2 = new SubType()
console.log(instance2.colors) // ['red', 'yellow']

思考一哈?

console.log(instance1.constructor) // SubType
console.log(SubType.prototype.constructor) // SubType
console.log(SubType.prototype.__proto__) // {}

console.log(instance1.__proto__ == SubType.prototype) // true
console.log(SubType.prototype.__proto__ == SuperType.prototype) // false
console.log(SubType.prototype.__proto__ == Object.prototype) // true

console.log(SubType.__proto__ == SuperType.prototype) // false
console.log(SubType.__proto__ == Function.prototype) // true

console.log(SuperType.prototype.constructor == SuperType) // true
console.log(SuperType.__proto__ == Function.prototype) // true
console.log(SuperType.prototype.__proto__ == Object.prototype) // true

構造函數,原型對象,實例對象