javascript
JS中原型与原型链
一. 普通對象與函數對象
JavaScript 中,萬物皆對象!但對象也是有區別的。分為普通對象和函數對象,Object 、Function等 是 JS 自帶的函數對象。下面舉例說明。
var o1 = {}; var o2 =new Object(); var o3 = new f1();function f1(){}; var f2 = function(){}; var f3 = new Function('str','console.log(str)');console.log(typeof Object); //function console.log(typeof Function); //function console.log(typeof f1); //function console.log(typeof f2); //function console.log(typeof f3); //function console.log(typeof o1); //object console.log(typeof o2); //object console.log(typeof o3); //object 在上面的例子中 o1 o2 o3 為普通對象,f1 f2 f3 為函數對象。怎么區分,其實很簡單,凡是通過 new Function() 創建的對象都是函數對象(Function),其他的都是普通對象(Object)。f1,f2,歸根結底都是通過 new Function()的方式進行創建的。Function Object也都是通過 New Function()創建的。二. 原型對象
function Person(){} Person.prototype.name = 'test'; Person.prototype.age = 28; Person.prototype.job = 'Software Engineer'; Person.prototype.sayName = function() {alert(this.name); }var person = new Person();
在 JavaScript 中,每當定義一個對象(函數也是對象)時候,對象中都會包含一些預定義的屬性。其中每個函數對象都有一個prototype屬性,這個屬性指向函數的原型對象。而原型對象他本身就是一個普通對象(沒有通過 new Function() 創建的對象都是普通對象),即原型對象就是Person.prototype,如果你還是害怕它,那就把它想想成一個字母 A:var A = Person.prototype。這里要強調一點,只有函數對象才會擁有prototype屬性,但是每個對象都擁有__proto__屬性(null除外)。
在上面我們給A添加了四個屬性:name、age、job、sayName。其實它還有一個默認的屬性:constructor。在默認情況下,所有的原型對象都會自動獲得一個?constructor(構造函數)屬性,這個屬性(是一個指針)指向?prototype屬性所在的函數(Person)。即:Person.prototype.constructor == Person。當我們創建對象var person = new Person()時,person可以繼承原型對象Person.prototype的constructor屬性,因此person.constructor == Person,注意person這個實例本身是沒有constructor,實例的constructor是通過原型鏈(__proto__)獲取原型對象上邊的constructor。
person.constructor == Person Person.prototype.constructor == Person從這一角度,我們可以將Person.prototype理解為Person的一個實例。(但其實原型對象(Person.prototype)并不是構造函數(Person)的實例,而是構造函數的屬性,而且是預定義添加的)。
var A = new Person(); Person.prototype = A;但是有一個非常特別的原型對象:Function.prototype,它并不是普通對象,而是函數對象,而這個函數對象卻沒有prototype屬性(前面所說的“每個函數對象都有一個prototype屬性,這個屬性指向函數的原型對象”,對Function.prototype并不適用)。
function Person(){}; console.log(typeof Person.prototype) //Object console.log(typeof Function.prototype) // Function,這個特殊 console.log(typeof Object.prototype) // Object console.log(typeof Function.prototype.prototype) //undefinedFunction.prototype為什么是函數對象呢?
var A = new Function();Function.prototype = A;上文提到過凡是通過凡是通過 new Function() 創建的對象都是函數對象,其他的都是普通對象。因為 A 是函數對象,所以Function.prototype是函數對象。
三. __proto__
JS 在創建對象(不論是普通對象還是函數對象)的時候,都有一個叫做__proto__的內置屬性,用于指向創建它的構造函數的原型對象。對象 person有一個__proto__屬性,創建它的構造函數是Person,構造函數的原型對象是Person.prototype ,所以:person.__proto__ == Person.prototype
Person.prototype.constructor == Person; person.__proto__ == Person.prototype; person.constructor == Person;類似的,Person.__proto__ == Function.prototype;Person.prototype.__proto__ == Object.prototype;Object.__proto__ == Function.prototype;?Object.prototype.__proto__ == null,按照上述理解?Object.prototype是普通對象,而普通對象的構造函數是Object,那么Object.prototype.__proto__ ==?Object.prototype,從而在原型鏈上形成死循環無法終止,因此定義Object.prototype.__proto__ == null,null是原型鏈的頂端。
不過,要明確的真正重要的一點就是,這個連接存在于實例(person)與構造函數(Person)的原型對象(Person.prototype)之間,而不是存在于實例(person)與構造函數(Person)之間。
var animal = function(){}; var dog = function(){};animal.price = 2000; dog.prototype = animal; var tidy = new dog(); console.log(dog.price) //undefined console.log(tidy.price) // 2000實例(tidy)和 原型對象(dog.prototype)存在一個連接。這個連接存在于實例(tidy)與構造函數的原型對象(dog.prototype)之間,而不是存在于實例(tidy)與構造函數(dog)之間。
四. 函數對象
所有函數對象的__proto__都是指向Function.prototype,它是一個空函數。
Number.__proto__ === Function.prototype // true Number.constructor == Function //true Boolean.__proto__ === Function.prototype // true Boolean.constructor == Function //true String.__proto__ === Function.prototype // true String.constructor == Function //true// 所有的構造器都來自于Function.prototype,甚至包括根構造器Object及Function自身 Object.__proto__ === Function.prototype // true Object.constructor == Function // true// 所有的構造器都來自于Function.prototype,甚至包括根構造器Object及Function自身 Function.__proto__ === Function.prototype // true Function.constructor == Function //true Array.__proto__ === Function.prototype // true Array.constructor == Function //true RegExp.__proto__ === Function.prototype // true RegExp.constructor == Function //true Error.__proto__ === Function.prototype // true Error.constructor == Function //true Date.__proto__ === Function.prototype // true Date.constructor == Function //true所有的構造器都來自于Function.prototype,甚至包括根構造器Object及Function自身。所有構造器都繼承了Function.prototype的屬性及方法。Function.__proto__ ==?Function.prototype,而前面說過,Function.prototype它不是普通對象,而是函數對象,那么Function.prototype.__proto__ == ?,按照上述,Function.prototype.__proto__ ==?Function.prototype,但又出現了原型鏈上的死循環,JS一直強調萬物皆對象,函數對象也是對象,給他認個祖宗,指向?Object.prototype,Object.prototype.__proto__ == null,保證原型鏈能夠正常結束。
特別的,Math,JSON是以普通對象形式存在的。
Math.__proto__ === Object.prototype // true Math.construrctor == Object // true JSON.__proto__ === Object.prototype // true JSON.construrctor == Object //true四. 總結
原型和原型鏈是JS實現繼承的一種模型。
原型鏈的形成是真正是靠__proto__而非prototype。
參考資料:https://www.jianshu.com/p/dee9f8b14771
轉載于:https://www.cnblogs.com/RainyBear/p/8612560.html
總結
- 上一篇: 在win10中通过Anaconda3安装
- 下一篇: codefroces 297E Myst