1.prototype
在JavaScript中,每個函數都有一個prototype屬性,這個屬性指向函數的原型對象。
<script type="text/javascript">
//每一個函數都由一個prototype,預設指向一個object
console.log(Date.prototype,typeof Date.prototype)
function fun() {
console.log("test")
}
console.log(fun.prototype,typeof fun.prototype)
fun.prototype.test = function () {
alert("1")
}
console.log(fun.prototype,typeof fun.prototype)
//原型對象有一個屬性contructor,預設指向函數對象
console.log(fun.prototype.constructor === fun)//fun
console.log(Date.prototype.constructor === Date)
//建立一個執行個體,
var f1 = new fun()
f1.test()
</script>
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI0gTMx81dsQWZ4lmZf1GLlpXazVmcvwFciV2dsQXYtJ3bm9CX9s2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xCMy81dvRWYoNHLwEzX5xCMx8FesU2cfdGLwMzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5iN4YzN5cTNwIWMhRTZmRGOyYzXyQDMwgTM1IzLcVDMyIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjLyM3Lc9CX6MHc0RHaiojIsJye.png)
上述例子中,函數的prototype指向了一個對象,而這個對象正是調用構造函數時建立的執行個體的原型,也就是person1和person2的原型。
原型的概念:每一個javascript對象(除null外)建立的時候,就會與之關聯另一個對象,這個對象就是我們所說的原型,每一個對象都會從原型中“繼承”屬性。
讓我們用一張圖表示構造函數和執行個體原型之間的關系:
2.proto
<script type="text/javascript">
//顯示屬性:prototype
//隐式屬性:__proto__
function fun() {
}
console.log(fun.prototype)
var f1 = new fun()
console.log(f1.__proto__ === fun.prototype)
</script>
圖的關系:
補充說明:
絕大部分浏覽器都支援這個非标準的方法通路原型,然而它并不存在于 Person.prototype 中,實際上,它是來自于 Object.prototype ,與其說是一個屬性,不如說是一個 getter/setter,當使用 obj.proto 時,可以了解成傳回了 Object.getPrototypeOf(obj)。
3.constructor
每個原型都有一個constructor屬性,指向該關聯的構造函數。
<script type="text/javascript">
//每一個函數都由一個prototype,預設指向一個object
console.log(Date.prototype,typeof Date.prototype)
function fun() {
console.log("test")
}
console.log(fun.prototype,typeof fun.prototype)
fun.prototype.test = function () {
alert("1")
}
console.log(fun.prototype,typeof fun.prototype)
//原型對象有一個屬性contructor,預設指向函數對象
console.log(fun.prototype.constructor === fun)//fun
console.log(Date.prototype.constructor === Date)
//建立一個執行個體,
var f1 = new fun()
f1.test()
</script>
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI0gTMx81dsQWZ4lmZf1GLlpXazVmcvwFciV2dsQXYtJ3bm9CX9s2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xCMy81dvRWYoNHLwEzX5xCMx8FesU2cfdGLwMzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5iN4YzN5cTNwIWMhRTZmRGOyYzXyQDMwgTM1IzLcVDMyIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjLyM3Lc9CX6MHc0RHaiojIsJye.png)
圖:
4.執行個體與原型
當讀取執行個體的屬性時,如果找不到,就會查找與對象關聯的原型中的屬性,如果還查不到,就去找原型的原型,一直找到最頂層為止。
function Person() {
}
Person.prototype.name = 'Kevin';
var person = new Person();
person.name = 'Daisy';
console.log(person.name) // Daisy
delete person.name;
console.log(person.name) // Kevin
在這個例子中,我們給執行個體對象 person 添加了 name 屬性,當我們列印 person.name 的時候,結果自然為 Daisy。
但是當我們删除了 person 的 name 屬性時,讀取 person.name,從 person 對象中找不到 name 屬性就會從 person 的原型也就是 person.proto ,也就是 Person.prototype中查找,幸運的是我們找到了 name 屬性,結果為 Kevin。
5.原型的原型
原型也是一個對象
var obj = new Object()
obj.name = "Zjy"
console.log(obj.name)
其實原型對象就是通過 Object 構造函數生成的,結合之前所講,執行個體的 proto 指向構造函數的 prototype ,是以我們再更新下關系圖:
6.原型鍊
簡單的回顧一下構造函數、原型和執行個體的關系:每個構造函數都有一個原型對象,原型對象都包含一個指向構造函數的指針,而執行個體都包含一個指向原型對象的内部指針。那麼假如我們讓原型對象等于另一個類型的執行個體,結果會怎樣?顯然,此時的原型對象将包含一個指向另一個原型的指針,相應地,另一個原型中也包含着一個指向另一個構造函數的指針。假如另一個原型又是另一個類型的執行個體,那麼上述關系依然成立。如此層層遞進,就構成了執行個體與原型的鍊條。這就是所謂的原型鍊的基本概念。
console.log(Object.prototype.__proto__ === null)