今天繼續深入探索面向對象編程
前面講到數組實例的原型是Array.prototype,函數實例的原型是Function.prototype,對象的原型則是Null(這一點前面沒講)
但是所有實例,都是由以構造函數為原型實例化出來的
而構造函數,是指上就是函數,函數的構造函數就是Function
下面我們先看一個實例,了解一下構造函數
構造函數是怎么一回事?
var 數組 = new Array()
數組.__proto__===Array.prototype
//true
Array.__proro__===Function.prototype
//true
Array.prototype.__proto__===Object.prototype
//true
數組.__proto__.__proto__===Object.prototype
//true
var 函數 = new Function()
函數.__proto__===Function.prototype
//true
Function.__proto__===Function.prototype
/true
Function.prototype.__proto__===Object.prototype
//true
函數.__proto__.__proto__===Object.prototype
//true
var 對象 = new Object()
對象.__proto__===Object.prototype
//true
Object.__proto__===Function.prototype
//true
Object.prototype.__proto__===null
true
上面的代碼說明,proto屬性指向prototype屬性
prototype屬性則是實例的原型
即proto指向實例的原型
實戰一下,案例里Animal是Person的原型
function Animal(wuzhong){
this.wuzhong = wuzhong
}
Animal.prototype.run = function(){
console.log('I am running!')
}
function Person(name){
Animal.call(this,'renlei')
//對Animal.wuzhong屬性傳參數
console.log(this.wuzhong==='renlei')
this.name = name
}
Person.prototype.sayhi = function(){
console.log('nice to you!')
}
var llz = new Person('llz')
console.dir(llz)
雖然這種形式,可以讓Person構造函數的實例也繼承Animal的屬性,
但是Person的原型對象的proto并沒有繼承Animal的原型對象
實例的原型能再繼承其它的原型嗎?(適合IE11以上版本)
function Animal(wuzhong){
this.wuzhong = wuzhong
}
Animal.prototype.run = function(){
console.log('I am running!')
}
function Person(name){
Animal.call(this,'renlei')
console.log(this.wuzhong==='renlei')
this.name = name
}
Person.prototype.__proto__=Animal.prototype
Person.prototype.sayhi = function(){
console.log('nice to you!')
}
var llz = new Person('llz')
console.dir(llz)
所以需要再指定一下Person的原型繼承Animal的原型,
加上這句代碼Person.prototype.__proto__=Animal.prototype
但是proto屬性只在IE11以上版本
所以如果需要兼容更低版本的IE,需要換一種方式繼承原型
兼容IE更低的版本(IE9)
Person.prototype=Object.create(Animal.prototype)
能兼容到IE9
但是由于是直接賦值在Person.prototype屬性上,原有屬性被覆蓋
所以constructor屬性沒有了,如果需要這個屬性要重新賦值給它
Person.prototype.constructor=Person
還能兼容更低版本的IE(IE5.5)
Person.prototype=new Animal()
Person.prototype.constructor=Person
能兼容到IE5.5
還有其它方法也能兼容到(IE5.5)
function FakeAniaml(){}
FakeAniaml.prototype=Animal.prototype
Person.prototype=new FakeAniaml()
也能兼容到IE5.5,
但不用再重新對constructor賦值
接下來了解一下,對實例的屬性取值
function Person(name){
this.name = name
}
Person.prototype.物種 = 'animal'
Person.prototype.sayhi = function(){
console.log(`Hi,I am ${this.name}`)
}
var llz = new Person('llz')
llz.age = 22
llz.sayhi()
console.log(llz.物種===Person.prototype.物種)
console.dir(llz)
Hi,I am llz
true
Person:{
name:'llz'
age:22
prototype:{
sayhi:function(){}
物種:'animal'
}
}
對實例的屬性取值,如果構造函數上沒有,
則會在原型鏈上尋找有沒有該屬性,
有就會去原型鏈上取該屬性的值
llz.物種='plant'
console.log(llz.物種)
'animal'
由于屬性是在原型鏈上,構造函數的原型上并沒有對應屬性,
則不會修改該屬性的值
對實例的賦值
llz.__proto__.物種 = 'plant'
如果需要賦值,必須在其原型鏈上,
有該屬性的原型對象修改該屬性的值
如果要對原始的javascript對象的原型屬性修改,該怎么辦
比如對數值基本類型,調用自定義的函數,
可以在對應的Number復合對象的原型上的屬性增加函數
console.log(1.234.toFixed(1))
Number.prototype.twice = function(){
return this.valueOf()*2
}
1..twice().twice()
1.2
4
上面案例證明了兩點
基本類型能調用對應復合類型的屬性函數
在復合類型的原型上增加新的屬性,可以被復合類型對應的所有的實例調用
接下來介紹用ES6的class語法,實現原型的基礎
class Animal{
constructor(物種){
this.物種 = 物種
}
introduce(){
console.log(`I am ${this.物種}!`)
}
}
class Person extends Animal{
constructor(name){
super('person')
this.name = name
}
sayhi(問候語){
console.log(`Hi,I am ${this.name},${問候語}`)
}
}
var llz = new Person('llz')
console.dir(llz)
llz.sayhi('好久不見!最近還好嗎?')
Person
name:"llz"
物種:"person"
__proto__:{
constructor:class Person
sayhi:sayhi(問候語){}
__proto__:{
constructor:class Animal
introduce:(問候語){}
__proto__:{
constructor:Object
原生Object封裝的屬性
……………………
}
}
}
extends是構造函數的原型用來繼承其它構造函數,
super調用繼承的原型的構造函數上的屬性方法
如果要在Person原型上增加屬性值
class Person extends Animal{
constructor(name){
super('person')
this.name = name
}
get 物種(){
return '人類'
}
sayhi(問候語){
console.log(`Hi,I am ${this.name},${問候語}`)
}
}