JavaScript 原型對象

JavaScript是一種基于對象的語言,可以說萬物皆對象。
??特別說明:基于對象也好,面向?qū)ο笠埠脤嶋H上都是以對象的概念來編寫程序,從本質(zhì)上并無區(qū)別。
??JavaScript沒有類這個概念,它繼承機制是基于原型,產(chǎn)生原型鏈的模式,而不是其他語言的類。因此要理解JavaScript的繼承機制,需要更深入了解原型對象的概念。

對象
??JavaScript中,對象是有區(qū)別的,分為普通對象和函數(shù)對象,Object、Function是JS自帶的函數(shù)對象,function定義方式本質(zhì)上還是new Function方式。(函數(shù)對象都是通過Function來實例化的)

        <script type="text/javascript">
            function f1(){};
            var f2 = function(){};
            var f3 = new Function('str', 'console.log(str)');
            var o3 = new f1();
            var o1 = {};
            var o2 = new Object();
            
            console.log(typeof Object);//function
            console.log(typeof Function);//function
            console.log(typeof o1);//object
            console.log(typeof o2);//object
            console.log(typeof o3);//object
            console.log(typeof f1);//function
            console.log(typeof f2);//function
            console.log(typeof f3);//function
        </script>

在上面的例子中 o1 o2 o3 為普通對象,f1 f2 f3 為函數(shù)對象。怎么區(qū)分,其實很簡單,凡是通過 new Function() 創(chuàng)建的對象都是函數(shù)對象,其他的都是普通對象。f1,f2,歸根結(jié)底都是通過 new Function()的方式進行創(chuàng)建的。Function Object 也都是通過 new Function()創(chuàng)建的。

對象繼承
??Brendan Eich參考C++和Java,做了簡化設(shè)計,將new命令引入到JavaScript中,new后面跟對象的構(gòu)造函數(shù),用來創(chuàng)建對象,缺點:無法共享方法和屬性。

比如,在DOG對象的構(gòu)造函數(shù)中,設(shè)置一個實例對象的共有屬性species。(函數(shù)也是一個對象)
function DOG(name) {
  this.name = name;
  this.species = '犬科';
};
用上面**函數(shù)對象**生成兩個實例對象
var dogA = new DOG('大毛');
var dogB = new DOG('二毛');

這兩個對象species屬性是獨立的,修改其中一個,不會影響到另一個。
dogA.species = '貓科';
alert(dogB.species);//犬科
每個實例對象都有自己的屬性和方法的副本,這不僅無法做到資源共享,也極大的資源浪費。

Brendan Eich決定為構(gòu)造函數(shù)設(shè)置一個prototype屬性。這個屬性包含一個對象,所有實例對象需要共享的屬性和方法,都放在這個對象里面;那些不需要共享的屬性和方法,就在構(gòu)造函數(shù)里面。實例對象一旦創(chuàng)建,將自動引用prototype對象的屬性和方法(也就是__proto__)。也就是說,實例對象的屬性和方法,分成兩種,一種是本地的,另一種是引用的。

species屬性放在prototype對象里,是兩個實例對象共享的。只要修改了prototype對象,就會同時影響兩個實例對象。
DOG.prototype.species = '貓科';
alert(dogA.species);//貓科 (dogA的__proto__指向DOG.prototype)
alert(dogB.species);//貓科

由于所有實例對象共享一個prototype對象,那么從外界看起來,prototype對象就好像是實例對象的原型,而實例對象則好像"繼承"了prototype對象一樣。

原型prototype
??在JavaScript中,每當定義一個對象(函數(shù))時候,對象都會包含一些預(yù)定的屬性。其中函數(shù)對象的一個屬性就是原型對象prototype(原型對象還有constructor屬性(指向構(gòu)造函數(shù)對象))。普通對象沒有prototype,但是有__proto__屬性。(比如實例化、字面量的對象)(指向其原型鏈)

原型對象其實就是普通對象(Function.prototype除外,它是函數(shù)對象,但它很特殊,他沒有prototype屬性(前面說道函數(shù)對象都有prototype屬性))。
function f1(){};
console.log(f1.prototype);//f1{}  (f1{}表示普通對象)
console.log(typeof f1.prototype);//object
console.log(typeof Function.prototype);//function,這個特殊
console.log(typeof Object.prototype);//object
console.log(typeof Function.prototype.prototype);//undefined
打印關(guān)于f1函數(shù)對象的相關(guān)信息

原型鏈
??JS在創(chuàng)建對象(不論普通對象還是函數(shù)對象)的時候,都有一個叫做__proto__([[ prototype ]] )的內(nèi)置屬性,用于指向創(chuàng)建它 的 函數(shù)對象的原型對象prototype。
??(ps:函數(shù)對象來自Function對象,字面量對象來自O(shè)bject對象,實例對象來自創(chuàng)建它的函數(shù)對象-->等等類似)

var person = function(name) {
    this.name = name;
};
person.prototype.getName = function() {
    return this.name;
}
var gz = new person('gongzi');
gz.getName();//gongzi

以上面的例子為例:

console.log(gz.__proto__ === person.prototype) //true

同樣,person.prototype對象也有__proto__屬性,它指向創(chuàng)建它的函數(shù)對象(Object)的prototype
console.log(person.prototype.__proto__ === Object.prototype) //true

繼續(xù),Object.prototype對象也有__proto__屬性,但它比較特殊,為null
console.log(Object.prototype.__proto__) //null

我們把這個有__proto__串起來的直到Object.prototype.__proto__為null的鏈叫做原型鏈。
如圖.png
function Fruits(name) {
    this.name = name;
}
Fruits.prototype.colour = 'red';
Object.prototype.taste = '甜';
var fruits = new Fruits('蘋果');
console.log(fruits);//打印實例對象(普通對象)

var Game = {
    name:'王者榮耀'
};
Object.prototype.type = '競技';
console.log(Game);//打印字面量對象(普通對象)

console.log(Fruits.__proto__);//打印 創(chuàng)建它 的 函數(shù)對象 的原型對象,結(jié)果function () {}
console.log(Fruits.constructor);//可以打印出構(gòu)造函數(shù)對象Function//Fruits.__proto__.constructor一樣
Function對象作為一個函數(shù),就會有prototype屬性,該屬性將對應(yīng)”function () {}”對象。
alert(Fruits.__proto__ === Function.prototype);//true

前面有提到,原型對象屬于普通對象。Function.prototype是個例外,它是原型對象,卻又是函數(shù)對象,作為一個函數(shù)對象,它又沒有prototype屬性。
打印實例對象.png
打印字面量對象.png

constructor屬性
??constructor 屬性返回對創(chuàng)建此對象的函數(shù)的引用
??prototype對象有一個construction屬性,默認指向prototype對象所在的構(gòu)造函數(shù)。
??由于construction屬性定義在prototype對象上面,意味著可以被所有實例對象繼承。
??constructor屬性的作用,是分辨原型對象到底屬于哪個構(gòu)造函數(shù)。

總結(jié)
1.原型和原型鏈是js實現(xiàn)繼承的一種模式。
2.原型鏈的形成真正的是靠proto而非prototype。

訪問原型對象的方法
獲取實例對象的原型對象,有三種方法:
1.obj.construction.prototype或者C.prototype用于引用new C()創(chuàng)建的對象的原型對象
2.Object.getPrototypeOf(obj):是獲取obj對象的原型對象的標準方法。
3.obj.proto:是獲取obj對象的原型對象的非標準方法,每個對象都有的屬性,可以在不支持Object.getPrototypeOf方法時作為權(quán)宜之計,proto是非安全的。
??上面三種方法第一種和第三種都不是很可靠。最新的ES6標準規(guī)定,proto屬性只有瀏覽器才需要部署,其他環(huán)境可以不部署,obj.construction.prototype在手動改變原型對象時,可能會失效。

擴展

1.Object.__proto__ === Function.prototype//true
2.Function.__proto__ === Function.prototype//true
3. Function.prototype.__proto__ === Object.prototype//true
1.Object是函數(shù)對象,是通過new Funciton()創(chuàng)建,所以O(shè)bject.__proto__指向Function.prototype。

2.Function也是對象函數(shù),也是通過new Function()創(chuàng)建,所以Function.__proto__指向Function.prototype。

3.Function.prototype是個函數(shù)對象,理論上其__proto__應(yīng)該指向Functuin.prototype,就是它自己,自己指向自己,沒有意義。函數(shù)對象也是對象,給它設(shè)定根指向Object.prototype,Object.prototype.__proto__ === null,保證原型鏈能夠正常結(jié)束。

Object.create()
??創(chuàng)建一個具有指定原型且可選擇性地包含指定屬性的對象。
Object.create(prototype, descriptors)
??這種創(chuàng)建對象的方式與上面所說略有差異,如果要查找原型鏈,按照原型對象的類型分析就可以。
??是使用第一個參數(shù)作為它們的原型。
prototype
??必需。要用作原型的對象。可以為 null,不繼承任何對象。
descriptors
??可選。包含一個或多個屬性描述符的 JavaScript 對象。
??“數(shù)據(jù)屬性”是可獲取且可設(shè)置值的屬性。 數(shù)據(jù)屬性描述符包含 value 特性,以及 writable、enumerable 和 configurable 特性。
使用方法可以參考網(wǎng)絡(luò)上的這兩篇,或自己百度,沒時間細說了。
javascript一種新的對象創(chuàng)建方式-Object.create()
前端開發(fā)者進階之ECMAScript新特性【一】--Object.create

參考文獻:
Javascript繼承機制的設(shè)計思想
JavaScript原型及原型鏈詳解
JS原型、原型鏈深入理解

實在不懂就就就.............這樣記住吧
??JS中所有函數(shù)的原型都是Function.prototype,所有對象原型鏈的終點指向Object.prototype

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容