摘要:中有基本類型和復雜類型的區(qū)分。原型與原型鏈這里,就引入了兩個新的概念。原型對象就是用來存放聲明對象中共有的那部分屬性。而原型對象自身也是一個對象,它也有自己的原型對象。這樣層層上溯,就形成了一個類似鏈表的結構,這就是原型鏈。
JavaScript中有基本類型和復雜類型的區(qū)分。
當我們在聲明一個基本類型時:
var n1= 1; console.log(n1); //1
這時我們可以用Number方法將1包裝為對象,即聲明一個對象1。
var n2= new Number(1); console.log(n2); //Number {1} //[[PrimitiveValue]]:1 //△__proto__: Number //constructor: ? Number() //toExponential: ? toExponential() //toFixed: ? toFixed() //toLocaleString: ? toLocaleString() //toPrecision: ? toPrecision() //toString: ? toString() //valueOf: ? valueOf() //__proto__: Object
n2的PrimitiveValue(初始值)為1,其實此時它就是一個hash。
此時對象n2現(xiàn)在有很多方法,可以調(diào)用對應各自的函數(shù)。
但是,我們發(fā)現(xiàn)有一點:在我們直接聲明基本數(shù)據(jù)類型n1時,也可以使用這些方法調(diào)用函數(shù)。
比如toString方法:
var n1= 1; n1.toString(); //"1"
這就要涉及到JavaScript的發(fā)明歷史。在設計之初,它被要求:“長得像” Java。
當時的Java聲明一個對象,就是如此:
var n= new Number(1)
設計師在設計的同時,為了簡便快捷,也制定了我們最常用的聲明方式:
var n= 1
當然,這種方法肯定被JavaScript程序員所喜愛,第一種方法幾乎沒有人用。
但是有一個問題,如果直接聲明n,那么它就是一個數(shù)字。而基本數(shù)據(jù)類型是沒有屬性的。
這時候該如何調(diào)取各種方法呢?
聲明一個臨時對象,我們暫將它稱為temp。
比如在對n進行toString方法引用時,會聲明一個臨時對象,對n進行復雜封裝,將其變?yōu)閷ο蟆?/p>
var n= 1; n.toString();
其實是:
var temp= new Number(n); temp.toString(); //1
將temp.toString的值賦予n.toString。在操作結束后,臨時對象將從內(nèi)存中抹除。
共用屬性number,string,boolean,object都有一些共同的方法,比如toString,valueof等等。為了避免重復聲明和內(nèi)存浪費,這些方法“歸納”與一個共用屬性之中。
JavaScript在聲明一個對象后,并不是先默認復制一遍共用屬性在內(nèi)存中的存放地址,再在引用時調(diào)取對應的函數(shù)。而是:
在聲明對象時,就存入一個隱藏的屬性:__proto__。該屬性,對應其共用屬性。
var obj= { name: "Jack", age: 18 }; console.log(obj); //△{name:"Jack", age:18} //age: 18 //name: "Jack" //△__proto__: Object //constructor: ? Object() //hasOwnProperty: ? hasOwnProperty() //isPrototypeOf: ? isPrototypeOf() //propertyIsEnumerable: ? propertyIsEnumerable() //toLocaleString: ? toLocaleString() //toString: ? toString() //valueOf: ? valueOf() //__defineGetter__: ? __defineGetter__() //__defineSetter__: ? __defineSetter__() //__lookupGetter__: ? __lookupGetter__() //__lookupSetter__: ? __lookupSetter__() //get __proto__: ? __proto__() //set __proto__: ? __proto__()
那我們在調(diào)用toString方法時:
JavaScript首先會檢查數(shù)據(jù)類型是否是對象;若不是,則包裝為對象作臨時的轉(zhuǎn)換。
然后,在檢查對象中是否有toString這個屬性;若沒有,才進入共用屬性進行檢查。
兩個空對象是不相等的,但他們的共有屬性是相等的。
var obj1= {}; console.log(obj1); //{} var obj2= new Object(); console.log(obj2); //{} obj1 === obj2; //false obj1.__proto__ === obj2.__proto__; //true
但是,當我們聲明一個number為對象時,它就有自己區(qū)別于普通對象的獨特的共有屬性。
比如toFixed,toExponential等等。
那么它的__proto__屬性就對應自己獨有的共同屬性,在共同屬性中還有另一個隱藏屬性__proto__對應一般對象的共有屬性。這樣,number類型的對象就可以調(diào)用所有的函數(shù)。
這里,就引入了兩個新的概念。
那么,這個共有屬性,就被稱為原型(對象)。原型對象就是用來存放聲明對象中共有的那部分屬性。
JavaScript中所有的對象都可以繼承其原型對象的屬性。
而原型對象自身也是一個對象,它也有自己的原型對象。這樣層層上溯,就形成了一個類似鏈表的結構,這就是原型鏈。
為了避免對原型對象在沒有被使用時被內(nèi)存清理,JavaScript通過prototype來默認引用。
Object.prototype
Object.prototype; //constructor: ? Object() //hasOwnProperty: ? hasOwnProperty() //isPrototypeOf: ? isPrototypeOf() //propertyIsEnumerable: ? propertyIsEnumerable() //toLocaleString: ? toLocaleString() //toString: ? toString() //valueOf: ? valueOf() //__defineGetter__: ? __defineGetter__() //__defineSetter__: ? __defineSetter__() //__lookupGetter__: ? __lookupGetter__() //__lookupSetter__: ? __lookupSetter__() //get __proto__: ? __proto__() //set __proto__: ? __proto__()
Number.prototype
Number.prototype; //constructor: ? Number() //toExponential: ? toExponential() //toFixed: ? toFixed() //toLocaleString: ? toLocaleString() //toPrecision: ? toPrecision() //toString: ? toString() //valueOf: ? valueOf() //__proto__: Object //[[PrimitiveValue]]: 0
如此,還有:
String.prototype
Boolean.prototype
等等。
Object.prototype.__proto__ === null
我們制作一個簡單的示意圖,以便更直觀地理解這些概念。
那么我們可以得到關系:
var obj= {}; obj.__proto__ === Object.prototype; //true var n= new Number(1); n.__proto__ === Number.prototype; //true n.__proto__.__proto__ === Object.prototype; //true總結起來,得到的結論就是:
Object.prototype是Object的共用屬性
obj.__proto__是Object的共用屬性的引用
同理,對于String、Boolean、Symbol和Number也是如此
文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/100235.html
摘要:在中,主要有兩種創(chuàng)建對象的方法分別是對象字面量以及調(diào)用構造函數(shù)對象字面量調(diào)用構造函數(shù)其實上述兩種創(chuàng)建對象的方法,本質(zhì)上是一樣的,都是引擎調(diào)用對象的構造函數(shù)來新建出一個對象。 原型與原型鏈是javascript里面最最核心的內(nèi)容,如果不能理解它們之間的存在關系的話,那么我們是不能理解這門語言的。 在JS中,主要有兩種創(chuàng)建對象的方法, 分別是對象字面量以及調(diào)用構造函數(shù) //對象字面量 va...
摘要:在講原型之前,先簡單介紹一下幾個概念構造函數(shù)例如上述代碼創(chuàng)建的函數(shù)就被稱為構造函數(shù)。同一個構造函數(shù)實例化得到的多個對象具有相同的原型對象,所以經(jīng)常使用原型對象來實現(xiàn)繼承。實例對象通過操作構造函數(shù)所創(chuàng)建的對象是實例對象。 對于很多前端開發(fā)者而言,JavaScript的原型實在是很讓人頭疼,所以我這邊就整理了一下自己對應原型的一點理解,分享給大家,供交流使用 原型 說起原型,那就不得不說p...
摘要:在講原型之前,先簡單介紹一下幾個概念構造函數(shù)例如上述代碼創(chuàng)建的函數(shù)就被稱為構造函數(shù)。同一個構造函數(shù)實例化得到的多個對象具有相同的原型對象,所以經(jīng)常使用原型對象來實現(xiàn)繼承。實例對象通過操作構造函數(shù)所創(chuàng)建的對象是實例對象。 對于很多前端開發(fā)者而言,JavaScript的原型實在是很讓人頭疼,所以我這邊就整理了一下自己對應原型的一點理解,分享給大家,供交流使用 原型 說起原型,那就不得不說p...
摘要:我們通過這個構造函數(shù)為原型對象添加其他方法和屬性。這個屬性存在與實例與構造函數(shù)的原型對象上直接,而不存在于實例與構造函數(shù)之間。李小花班花張全蛋張全蛋李小花李小花我們在遍歷對象的的屬性的時候,經(jīng)常需要判斷屬性是否來自于對象的原型還是屬性。 引言 上面說了創(chuàng)建對象有字面量方式和工廠模式還有構造函數(shù)模式,結果發(fā)現(xiàn)他們都各自有缺點,所以下面再給大家介紹幾種創(chuàng)建對象的方式,爭取能找到一種無痛的模...
閱讀 1324·2021-11-24 10:24
閱讀 4167·2021-11-22 15:29
閱讀 1099·2019-08-30 15:53
閱讀 2801·2019-08-30 10:54
閱讀 1987·2019-08-29 17:26
閱讀 1292·2019-08-29 17:08
閱讀 613·2019-08-28 17:55
閱讀 1591·2019-08-26 14:01