構造函數,原型對象,實例對象
阿新 • • 發佈:2019-02-25
解釋 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
構造函數,原型對象,實例對象