通過物件、建構函式深入理解js原型
說一些題外話
在最近的實習工作中因大量涉及到原生js的編寫,因此在工作之餘重新拿起紅寶書閱讀,每重新看一遍都受益匪淺,最近又讀到了js中難點原型、原型鏈,這裡僅是本人對js原型的理解和觀點,若有槽點錯誤之處,希望不吝賜教。
接下來我們就直奔主題
怎樣建立物件?建立物件方法有幾種?
使用建構函式建立物件
var M = function (name) {
this.name = name;
}
這是比較傳統建立物件的方法,這裡 M 為建構函式,當建立一個建構函式的時候,就為這個建構函式添加了一個 prototype 原型屬性表示M的原型物件,而在這個prototype 中自動生成了一個 constructor
用如下的UML圖便容易理解
console.log(M.prototype.constructor===M)//true
ok,理解了建構函式與prototype、constructor之間的關係,那麼例項與他們之間的關係是如何呢?
var m=new M("Bob");//例項化一個物件 m
當新建一個例項時就為 m 建立了__proto__ 或([[Prototype]]、< prototype >)屬性指向建構函式M的原型物件 prototype
注意:原型是m與M的prototype之間的聯絡,不是m與M之間的聯絡,換句話說建構函式與例項物件沒有直接關係 因此我們可以得出 例項物件的__proto__嚴格相等於 建構函式的 prototype物件
console.log(m.__proto__===M.prototype) // true console.log(m.constructor===M) // true
現在你理解了原型的概念了嗎? 如果還不太理解就繼續往下看…
函式M實際上也是Function型別的一個例項
這裡函式M是一個建構函式只是因為是大寫的M,用來區分普通的函式,但實際上他們沒什麼實質性的區別。 所以函式M實際上也是Function型別的一個例項
//Function引數列表所有引數都為字串型別,最後一個字串內容是要執行的函式程式碼,其餘字串為數量
// var functionname = new Function( [argname1, [... argnameN,]] body );
var M=new Function("name","this.name=name");
既然M也是一個例項物件,那麼它也有__proto__ 指向 它的建構函式的prototype 因此我們可以得出:
console.log(M.__proto__===Function.prototype); //true
console.log(M.constructor===Function); //true
console.log(Function.prototype.constructor===Function); //true
那麼 Function 有__proto__ 屬性嗎?
顯然是有的, 我們可別忘了函式也是一個物件,函式有自己的屬性和方法,因此你能說它不滿足物件的概念嗎? 所以Function 也是 Object 的一個 例項物件嗎? 答案是錯誤的。 前面我們說過誰是誰的例項物件就有__proto__ 指向它的建構函式的prototype
console.log(Function.constructor === Object) // false
console.log(Function.__proto__===Object.prototype); // fasle
console.log(Function.constructor === Function) // true
console.log(Function.__proto__===Function.prototype); // true
為什麼會這樣? 首先Function 不是 Object 的一個 例項物件, Function 還是Function 的例項物件 (Array、Function、Object 都是 Function 例項物件) 因此都有
console.log(Array.__proto__===Function.prototype) //true
console.log(Function.__proto__===Function.prototype) //true
console.log(Object.__proto__===Function.prototype) //true
而 Array、Function的 prototype 原型物件 才是 Object的 例項物件 既然 Function.prototype 是Object的例項物件 必然有__proto__ 指向建構函式的prototype
console.log(Function.prototype.__proto__=== Object.prototype) // true
console.log(Object.prototype.constructor===Object); // true
這就是我下一篇要講的原型鏈、繼承的概念 接下來還有一個疑問,Object有沒有__proto__ (原因前面已經講過) 噢不是 是
Object.prototype 有沒有__proto__?
答案是沒有的
console.log(Object.prototype.__proto__) //null
這就是原型鏈的終點,也是每一個例項物件原型的終點。
好現在我們已經瞭解了原型是怎樣產生的,並且具有什麼的特點,它與建構函式和例項物件之間的聯絡
m的建構函式是M
m.proto===M.prototype
M的建構函式是Function
M.proto===Function.prototype
Function的建構函式是Function
Function.proto===Function.prototype
Function.prototype的建構函式是Object
Function.prototype.proto===Object.prototype
Object的建構函式是Function
Object.proto===Function.prototype
Object的prototype沒有建構函式沒有__proto__
Object.prototype.proto===null
我們得出結論: 只有例項物件才有__proto__ 屬性,只有建構函式才有ptototype物件 且例項物件的__proto__指向建構函式的prototype 如果既是建構函式又是另一個建構函式的例項物件,那麼同時擁有__proto__ 和 prototype
使用物件字面量建立物件
var o = {
name: "ojbk",
age: 22
}
使用物件字面量建立物件是一種最常用的建立物件的方法, 前面我們說過當建立物件的時候就為新增__proto__ 指向建構函式的prototype
console.log(o.__proto__===Object.prototype); //true
console.log(Object.prototype.constructor===Object); //true
其實這裡本身就是對Object的一個例項物件
o2 = new Object({
ok: 'ok',
no: 'no'
})
console.log(o2.__proto__===Object.prototype); //true
console.log(Object.prototype.constructor===Object); //true
說到這兒相信同學們都理解了原型的基本概念了 其實還有一種建立物件的方法,
使用Object.create()建立物件
這種方法其實用在繼承方面較多,不過也是建立物件的一種簡便方法
// 通過Object.create()方法建立物件
(function () {
var OP = {
pname: "pname",
page: '22'
}
// 使用此方法強制把p.__proto__屬性指向OP物件 注意是OP物件 而不是OP.prototype
// OP物件沒有prototype屬性 只有建構函式才有prototype物件
// 因為Object是OP物件的建構函式,OP是Object的例項 因此Object才有prototype物件
var p = Object.create(OP);
console.log(p.constructor === OP); //false
console.log(p.__proto__ === OP); //true
console.log(p.constructor === Object); //true
console.log(OP.constructor === Object); //true
// OP是Object的例項 只有例項物件才有__proto__屬性
//且指向建構函式的prototype 原型物件
console.log(OP.__proto__ === Object.prototype);
})();
這裡其實是重寫原型,重寫原型是在原型鏈繼承方面的知識, 重寫原型後還會有一些其他的影響,有興趣的同學可以去了解了解。
總結
- 原型是怎樣產生的?
- 例項物件、建構函式、proto、prototype互相的聯絡
- 建立物件的幾種方式
- 原型鏈的終點是Object.prototype
- Array、Function、Object、都是Function 的例項物件
- Array.prototype、Function.prototype是Object的例項物件(原型鏈相關知識)