圖解原型
function Person() {//TODO}
var p = new Person();
代碼執行之前要經歷一個預解析的過程。function Person(){}
是函數聲明,p
也是聲明(p 沒有畫出來),聲明在預解析的時候完成。
- 內存情況
所以,在代碼開始運行時,構造函數 Person
在內存中已經存在了,所以代碼運行起來第一句話是要執行var p = new Person();
程序開始執行
- 執行 new 創建對象
- 執行構造函數
Person
初始化對象(給對象添加屬性) - 內存情況
- 賦值給變量 p
- 針對構造函數來說,Person類型對象是構造函數的實例對象
- 針對構造函數來說,神祕對象是構造函數的原型屬性
- 針對Person類型對象來說,神祕對象是Person類型對象的原型對象
/* 接上面的代碼 */
Person.prototype.good = function() {console.log("好");}
p.good(); //好
p
表示的對象默認連接到Person.prototype
,Person
類型對象中是不存在good
方法的,但是p
也可以訪問到good
方法,由此可見,噹噹前對象中不存在某屬性或方法時,會去神祕對象中去查找。所以可以說,當前對象(Person類型對象
)繼承自神祕對象;也可以說,當前的實例對象,繼承自其原型對象,這就是原型繼承
。
- 原型繼承
爲什麼使用原型
-
爲什麼屬性一般不放在原型上
- 屬性表示對象的特徵,是一種對象特有的東西,對象不一樣,屬性也應該不一樣。但如果放到原型上,那麼就會被所有對象共享
-
爲什麼方法可以放在原型上
- 屬性是對象特有的,但是這個對象的行爲應該是一樣的。比如人和人是不一樣的,但是人都會走路,吃飯,這就是行爲,每個人都是一樣的,所以可以將其放在原型中複用
-
如何修改原型
1、 利用對象的動態特性Student.prototype.sleep = function(){}
2 、利用直接替換
/* 構造函數.prototype.xxxx = vvvv */ /* 直接將原型進行了替換 */ Student.prototype = { sleep: function(){} study: function(){} }
- 第一種方式與第二種方式最大的不同是,第二種方式又創建出了一個對象,將原有的原型對象進行了替換,所以現在內存中又兩個對象;第一種做法是直接在原來的對象上添加屬性
分析以下題目
function Person() {}
Person.prototype.func = function () {
console.log("11111");
};
var p1 = new Person();
Person.prototype = {
func: function () {
console.log("2222");
}
};
var p2 = new Person();
p1.func();
p2.func();
- 預解析構造函數
- 構造函數原型屬性賦值
- var p1 = new Person();
- 原型屬性重新賦值,首先執行等號右邊的語句,也就是在內存中創建了一個對象
- var p2 = new Person();
- 此時構造函數的原型屬性已經指向了匿名對象,所以新創建的
Person
類型的對象的原型對象也指向匿名對象 - 從圖可以得知,
p1.func()
執行結果是1111
;p2.func()
執行結果是2222
總結:只要對象創建出來了,即使原型屬性被重新賦值,那麼也不會影響已經創建好的對象的功能