【相關推薦:、】
在JavaScript中,函數是一個包含屬性和方法的Function
型別的物件。而原型(Prototype)
就是Function
型別物件的一個屬性。
在函數定義時就包含了prototype
屬性,它的初始值是一個空物件。在JavaScript中並沒有定義函數的原型型別,所以原型可以是任何型別。
原型是用於儲存物件的共用屬性和方法的,原型的屬性和方法並不會影響函數本身的屬性和方法。
// Function型別的屬性->所有函數都具有的屬性 console.log(Function.prototype);//[Function] // 定義函數 function fn() { console.log('this is function'); } //原型的預設值是空物件 console.log(fn.prototype);//fn {} // 函數包含建構函式 ——> 所有參照型別其實都是建構函式 console.log(Number.prototype); //[Number: 0] console.log(Object.prototype);//{}
通過如下兩種方式可以獲取物件的原型,從而設定共用的屬性和方法:
prototype
屬性getPrototype
(obj)方法。function fn() { console.log('this is function'); } //使用存取物件的屬性語法結構 console.log(fn.prototype);//fn {} console.log(fn['prototype']);//fn {} //Object型別提供getPrototypeOf()方法 console.log(Object.getPrototypeOf(fn));//[Function]
Object.getOwnPropertyDescriptors()
方法用來獲取一個物件的所有自身屬性的描述符。
var result = Object.getOwnPropertyDescriptor(Object.prototype,'constructor'); console.log(result) //輸出結果如下: //{ // value: [Function: Object], // writable: true, // enumerable: false, // configurable: true // }
constructor是在建立函數的時候自動新增的,指向建構函式本身
通過如下兩種方式可以設定原型的屬性和方法:
建構函式.prototype.屬性名 = 屬性值 ;建構函式.prototype.方法名 = function(){} ;
當我們需要在原型上新增很多很多屬性的時候 一遍一遍的去寫
建構函式.prototype.屬性名
太麻煩了,可以直接修改整個prototype
建構函式.prototype = { 屬性名:屬性值, 方法名:function(){}}
function foo () {}foo.prototype = { constructor: foo, name: 'jam', age: 18, address: '北京市'}var fn = new foo()console.log(fn.address) // 北京市
每個物件中都會具有一個isPrototypeOf()
方法,該方法用來判斷一個物件是否是另一個物件的原型。
範例程式碼如下: // 通過初始化器方式定義物件 var obj = { name:'jam' } // 定義建構函式 function Hero() {} // 將物件obj賦值給建構函式Hero的原型 Hero.prototype = obj; // 通過建構函式建立物件 var hero = new Hero(); // isPrototypeOf()方法判斷指定物件是否是另一個物件的原型 var result = obj.isPrototypeOf(hero); console.log(result);//true
驗證了
obj
物件是hero
物件的原型
接下來我們使用一段程式碼來展開對原型鏈的認識:
場景:查詢obj物件身上的address屬性 js執行的步驟: 1. 會觸發get操作 2. 在當前的物件中查詢屬性 3. 如果沒有找到,這個時候會去原型鏈(__proto__)物件上查詢 1. 查詢到結束 2. 沒查詢到一直順著原型鏈查詢,直到查詢到頂層原型(頂層原型是什麼暫時賣個關子)
var obj = { name: 'jam', age: 19 } /* 要求:查詢obj物件身上的address屬性 */ // 原型鏈一層一層向上查詢,如果一直沒有找到,直到查詢到頂層原型結束 obj.__proto__ = {} obj.__proto__.__proto__ = {} obj.__proto__.__proto__.__proto__ = { address: '北京市' } console.log(obj.address) // 北京市 console.log(obj.__proto__.__proto__.__proto__) // { address: '北京市' }
最終查詢到address屬性
那麼這裡有一個問題,如果一直沒有查到,會無窮盡的去查詢嗎?接下來我們就來了解一下
上面我們說到,順著原型鏈不會無休止的去查詢,當查到頂層原型的時候,如果還沒查到就會返回undefined
。
那麼頂層原型是什麼呢?
範例程式碼如下:
var obj = { name: 'jam' }console.log(obj.__proto__) // {}console.log(obj.__proto__.__proto__) // null
字面量物件obj的原型是:
{}
。{}
就是頂層的原型
當我們繼續向上列印__proto__
時,返回一個null值,就證明上一層就已經是頂層原型了
如下圖是針對第一段程式碼中缺少的頂層原型做的補充:
頂層原型就是Object.prototype
3.1 那麼什麼地方是原型鏈的盡頭呢?比如第三個物件是否也有原型__proto__
屬性呢?
var obj = {name:'jam'}obj.__proto__ = {}obj.__proto__.__proto__ = {}obj.__proto__.__proto__.__proto__ = {}console.log(obj.__proto__.__proto__.__proto__.__proto__) // {}
我們發現上面列印結果為 空物件{}
var obj = { name: 'jam', age: 19 } console.log(obj.__proto__) // {} console.log(Object.prototype) // {} console.log(obj.__proto__ === Object.prototype) // true
Object是所有類的父類別
所以obj.__proto__其實就是Object.prototype ,console.log(obj.__proto__ === Object.prototype) // true
我們可以看出結果Object.prototype就是頂層原型
{}
3.2 那麼我們可能會問:{}
原型有什麼特殊的嘛?
console.log(obj.__proto__.__proto__.__proto__.__proto__.__proto__) // null
Object.prototype
的結果為空物件{},但它不是空的,只是裡面的屬性不可列舉而已,例如我們就列印constructor
屬性看看<!-- 可以看出是有constructor屬性的 ,並不是空的-->console.log(Object.prototype.constructor) // [Function: Object] <!-- constructor 指回了Object -->
Object.getOwnPropertyDescriptors()
方法獲取Object.prototype
中的所有自身屬性的描述符。console.log(Object.getOwnPropertyDescriptors(Object.prototype)) // 如下長截圖所示
【相關推薦:、】
以上就是JavaScript原型與原型鏈知識點詳解的詳細內容,更多請關注TW511.COM其它相關文章!