我是每天被自己菜醒的跳跳,嗯~就很菜!
我們所創建的每一個函數,解析器都會向函數添加一個屬性,prototype,這個屬性對應着一個對象,這個對象就是我們所謂的原型對象。
如果函數作爲普通函數調用prototype沒有任何作用的。
當函數以構造函數的形式調用時,他所創建的實例對象中都會有一個隱含屬性,指向該構造函數的原型,我們可以通過proto來訪問屬性。
<script type="text/javascript">
var a = function(){
console.log(this.name+"構造函數")
console.log(this)
}
var stuProty ={
like:function(){
console.log(this.name+"構造函數")
console.log(this)
},
b:function(){
console.log("喫飯睡覺打豆豆")
}
}
//構造函數
function student(name,age){
this.name = name;
this.age = age;
//創建一個全局變量name和age,這裏的name指向的是window
// this.like = a
}
student.prototype = stuProty
console.log(student)
// 利用構造函數自定義對象
var stu1 = new student('狗兒',12)
var stu2 = new student("狗三",22)
stu1.like()
stu2.like()
</script>
上述代碼的原型如下圖
此處有兩個原型的原因是,1處原型在代碼中student.prototype = stuProty有這一句,給他加了原型,然後1處的原型裏面的2原型指向student。
這樣一個原型裏面有另一個原型,就構成了一個原型鏈,
值得注意的是如果對象的屬性和原型裏的函數重名了,自己屬性的優先級會高於原型上的優先級,如下圖
stu1和stu2使用的是同一個構造函數創建出來的實例對象,他們兩個都有一個共同的原型函數like
在1處,給stu1加了一個屬性like=12345;-->這樣不會修改原型中同名like函數的樣子,只是給stu1加了一個屬性,在2處可以看出並沒有影響。
在3處在進行調用stu1的原型函數like時報錯,但是在4處可以調用stu1的屬性like,說明在stu1中同名的屬性比原型中的函數優先級要高。
在5處就可以看出,stu1的屬性和原型是共存的。
如果想調用stu1原型上like函數,使用stu1__proto__.like()來調用,如上圖,但是此處的this是發生了改變,指向了_porto__也就是構造函數,不是指向的stu1,所以報了undefined。
在2處使用.call來改變this的指向,將原型從指向構造函數改爲指向stu1.
當然儘量不要重名啦!
1.原型對象相當於一個公共區域,所有同一個類的實例都可以訪問到這個原型對象,我可以將對象中共有的內容,設置到原型對象中去。
2.使用原型對象在以後創建構造函數的時候,可以將對象共有的屬性和方法,同意添加到構造函數的原型對象中去,這樣就不用了分別爲每一個對象添加,不會佔內存,也不會影響到全局作用域。
3.使用in來檢查對象中是否含有某個屬性的時候,如果對象的屬性中沒有但是原型中有,也會返回true。可以使用對象的hasOwnProperty()來檢查對象自身中是否含有該屬性。
4.原型鏈,原型對象也是對象,所以他也有原型,當我們使用或者訪問一個對象的屬性或方法時:
- 他會先在對象自身去尋找,有則直接使用
- 沒有則會原型中去尋找,找到了則直接使用
- 再沒有則去原型的原型中去找,有則直接使用,一直找到Object對象的原型
- 還沒的話就返回null
從4處我們可以看處,想要改寫Object的toString方法,只需要在實例自身上寫一個相同名字的toString方法,來改寫我們原型上的方法,來達到我們的效果。需要注意的是不要直接去改Object的方法,否則的話全局的都改了,別人用就GG了。
本人是個菜逼,理解有錯誤的地方,歡迎指正。記錄下學習筆記。