摘要:深入理解中的屬性和特性中屬性和特性是完全不同的兩個概念,這里我將根據(jù)自己所學,來深入理解中的屬性和特性。其中第三個參數(shù)描述符對象是對象字面量的方法創(chuàng)建的,里面的屬性和屬性值實際上保存的是要修改的特性和特性值。
深入理解JavaScript中的屬性和特性
JavaScript中屬性和特性是完全不同的兩個概念,這里我將根據(jù)自己所學,來深入理解JavaScript中的屬性和特性。
主要內(nèi)容如下:
理解JavaScript中對象的本質(zhì)、對象與類的關系、對象與引用類型的關系
對象屬性如何進行分類
屬性中特性的理解
第一部分:理解JavaScript中對象的本質(zhì)、對象與類的關系、對象與引用類型的關系對象的本質(zhì):ECMA-262把對象定義為:無序屬性的集合,其屬性可以包含基本值、對象或者函數(shù)。即對象是一組沒有特定順序的值,對象的每個屬性或方法都有一個名字,而這個名字都映射到一個值。故對象的本質(zhì)是一個散列表:其中是一組名值對,值可以是數(shù)據(jù)或函數(shù)。
對象和類的關系:在JavaScript中,對象和類沒有任何關系。這是因為ECMAScript中根本就沒有類的概念,它的對象與其他基于類的語言中的對象是不同的。
對象和引用類型的關系:對象和引用類型并不是等價的,因為每個對象都是基于一個引用類型創(chuàng)建的。
第二部分:對象屬性如何進行分類由構造函數(shù)或對象字面量方法創(chuàng)建的對象中具有屬性和方法(只要提到屬性和方法,它們一定是屬于對象的;只要提到對象,它一定是具有屬性和方法的(自定義除外)),其中屬性又可分為數(shù)據(jù)屬性和訪問器屬性,他們的區(qū)別如下:
數(shù)據(jù)屬性一般用于存儲數(shù)據(jù)數(shù)值,訪問器屬性不包含數(shù)據(jù)值
訪問器屬性多用于get/set操作
第三部分:屬性中特性的理解ECMAScript為了描述對象屬性(property)的各種特征,定義了特性(attribute)這個概念。也就是說特性不同于屬性,特性是為了描述屬性的。下面,我將分別講解:
數(shù)據(jù)屬性及其特性
訪問器屬性及其特性
如何利用Object.defineProperties()方法定義多個特性
如何利用Object.getOwnPropertyDescripter()方法讀取屬性的描述符以讀取屬性的特性
1.數(shù)據(jù)屬性及其特性
剛剛我們說過,數(shù)據(jù)屬性是用于存儲數(shù)據(jù)數(shù)值的,因此數(shù)據(jù)屬性具有一個數(shù)據(jù)值的位置,在這個位置可以讀取和寫入值。數(shù)據(jù)屬性有4個描述其行為的特性,由于ECMAScript規(guī)定:在JavaScript中不能直接訪問屬性的特性(注意:不是不能訪問),所以我們把它放在兩組方括號中。如下:
[[Configurable]]:默認值為true,a、表示能否通過delete刪除屬性從而重新定義屬性 b、能否修改屬性的特性
c、能夠把屬性由數(shù)據(jù)屬性修改為訪問器屬性
[[Enumerable]]:默認值為true,表示能否通過for-in循環(huán)返回該屬性(所以:如果為false,那么for-in循環(huán)沒法枚舉它所在的屬性)
[[Writable]]:默認值為true,表示能否修改屬性的值,這是與[[Configurable]]不同之處。
[[Value]]:默認值為undefined,這個值即為屬性的屬性值,我們可以在這個位置上讀取屬性值,也可以在這個位置上寫入屬性值。
注意:上述的默認是指通過構造函數(shù)或對象字面量創(chuàng)建的對象所自身擁有的屬性,而不是下面要介紹的Object.defineProperty()方法
這些特性都具有默認值,但是如果這些默認值不是我們想要的,該怎么辦呢?當然就是修改啦!我們可以通過Object.defineProperty()方法來修改屬性默認的特性。英文difineProperty即為定義屬性的意思。這個方法接收三個參數(shù):屬性所在的對象、屬性的名字和一個描述符對象。其中第三個參數(shù)描述符對象是對象字面量的方法創(chuàng)建的,里面的屬性和屬性值實際上保存的是要修改的特性和特性值。
下面通過幾個例子來深入理解。
a
var person={}; Object.defineProperty(person,"name",{ writable:false, value:"zhuzhenwei" }); console.log(person.name);//zhuzhenwei person.name="heting"; console.log(person.name);//zhuzhenwei
這里我用對象字面量的方法創(chuàng)建了一個對象,但是沒有同時創(chuàng)建方法和屬性。而是利用了Object.defineProperty()方法來創(chuàng)建了屬性和修改了默認值。這里將writable設置為false,于是后面我試圖修改person.name時,是無效的。
b
var person={}; Object.defineProperty(person,"name",{ value:"zhuzhenwei" }); console.log(person.name);//zhuzhenwei person.name="heting"; console.log(person.name);//zhuzhenwei
注意看這個例子,這個例子中我刪去了writable:false,為什么還是不能修改呢?這是因為之前我在介紹特性時,前三個默認為ture,是在創(chuàng)建對象并創(chuàng)建屬性的情況下得到的。對于通過調(diào)用Object.defineProperty()方法創(chuàng)建的屬性,其前三個特性的默認值均為false,這里需要注意。
c
var person={}; Object.defineProperty(person,"name",{ value:"zhuzhenwei", configurable:false }); console.log(person.name);//zhuzhenwei delete person.name; console.log(person.name);//zhuzhenwei
這里我們將新建的屬性name的特性設置為了configurable:false;因此下面刪除屬性的操作是無效的。根據(jù)b,可知configurable,默認就是false,即使去掉也不可修改。
d
var person={}; Object.defineProperty(person,"name",{ value:"zhuzhenwei", configurable:true }); console.log(person.name);//zhuzhenwei delete person.name; console.log(person.name);//undefined
在這里我將默認的configurable的值由默認的false修改為了true,于是變成了可配置的,那么最后就成功刪除了。
e
var person={}; Object.defineProperty(person,"name",{ value:"zhuzhenwei", configurable:false }); console.log(person.name);//zhuzhenwei Object.defineProperty(person,"name",{ value:"zhuzhenwei", configurable:true }); console.log(person.name);//Uncaught TypeError: Cannot redefine property: name(…)
如果之前已經(jīng)設置成為了false,那么后面再改成true也是徒勞的,即:一旦把屬性設置成為不可配置的,就不能再把它變回可配置了。
f
console.log(person.name);//Uncaught TypeError: Cannot redefine property: name(…) var person={}; Object.defineProperty(person,"name",{ value:"zhuzhenwei", }); console.log(person.name);//zhuzhenwei Object.defineProperty(person,"name",{ value:"zhuzhenwei", configurable:true }); console.log(person.name);//Uncaught TypeError: Cannot redefine property: name(…)
這里可以說明,即使前一步我們不管默認的configurable:false,后面得到的仍是不可配置。于是,可以得出結論,為了可配置,必須在第一次調(diào)用Object.defineProperty()函數(shù)時就將默認的值修改為true。
2.訪問器屬性及其特性
之前提到,訪問器屬性不包含數(shù)據(jù)值,他們包含一對getter函數(shù)和setter函數(shù)(這兩個函數(shù)不是必須的)。在讀取訪問器屬性時,會調(diào)用getter函數(shù),這個函數(shù)負責返回有效的值;在寫入訪問器屬性是,會調(diào)用setter函數(shù)并傳入新值,這個函數(shù)負責決定如何處理數(shù)據(jù)。同樣,由于不能通過JavaScript來直接訪問得到訪問器屬性的特性,所以下面列出的特性將由[[]]括起來以作區(qū)分。
[[Configurable]]:默認值為true,a、表示能否通過delete刪除屬性從而重新定義屬性 b、能否修改屬性的特性c、能夠把屬性由訪問器屬性修改為數(shù)據(jù)屬性
[[Enumerable]]:默認值為true,表示能否通過for-in循環(huán)返回該屬性(所以:如果為false,那么for-in循環(huán)沒法枚舉它所在的屬性)
[[Get]]:在讀取屬性時調(diào)用的函數(shù)。默認值為undefined 關鍵:特性可以是一個函數(shù)
[[Set]]: 在寫入屬性時調(diào)用的函數(shù)。默認值為undefined 關鍵:特性可以是一個函數(shù)
由于get和set函數(shù)也屬于屬性的特性,那么他們就有可能(說有可能是因為這兩個函數(shù)也不是必須的)出現(xiàn)在Object.defineproperty的第三個參數(shù)描述符對象的屬性中。
注意:1.相對于數(shù)據(jù)屬性,我們發(fā)現(xiàn)訪問器屬性中沒有writable特性和value特性。這是因為訪問器屬性不包含數(shù)據(jù)值,那么我們怎么當然就不可修改屬性的值(用不到writable特性),更不用考慮value了。
2.訪問器屬性不能直接定義,必須是用Object.defineProperty()來定義。(通過這個規(guī)定我們就能準確地判斷出訪問器屬性和數(shù)據(jù)屬性了)
通過下面這個例子來深入理解:
var book={ _year:2004, edition:1 }; Object.defineProperty(book,"year",{ get:function(){
return this._year; }, set:function(newValue){ if(newValue>2004){ this._year=newValue; this.edition+=newValue-2004; } } }); book.year=2005; console.log(book.edition);//2
幾個需要深入理解的地方:
1.訪問器屬性不能直接定義,必須使用Object.defineProperty()來定義,且該屬性具有set和get特性,于是可以判斷,_year和edition是數(shù)據(jù)屬性,而year是訪問器屬性。
2.我們看到_year這個數(shù)據(jù)屬性前面是以_(下劃線)開頭的,這個一種常用的記號,用于表示只能通過對象方法訪問的屬性。從上面的例子中可以看到get相當于描述符對象的一個方法,而_year正是在這個對象方法訪問的屬性。而edition既可以通過對象方法訪問,也可以由對象直接訪問。
book.year表示正在讀取訪問器屬性,這時會調(diào)用get函數(shù),并返回了2004這個有效的值。
book.year=2005表示寫入訪問器屬性,這時會調(diào)用set函數(shù)并傳入新值,即將2005傳給newValue,這個函數(shù)決定如何處理數(shù)據(jù)。
這時使用訪問器屬性的常見方法-即設置一個屬性的值會導致其他屬性發(fā)生變化。
3.如何利用Object.defineProperties()方法定義多個特性
顯然,一個對象不可能只具有一個屬性,因此,定義多個屬性的可能性很大,于是JavaScript提供了Object.defineProperties()方法解決這個問題。這個方法接收兩個參數(shù),第一個是要定義屬性所在的對象,第二個是一個對象字面量方法創(chuàng)建的對象,對象的屬性名即為要定義的特姓名,對象的屬性值又是一個對象,這個對象里的屬性名和屬性值分別是特性名和特性值(這里不是很好理解,看例子即可)。
var book={}; Object.defineProperties(book,{ _year:{ writable:true, value:2004 }, edition:{ writable:true, value:1 }, year:{ get:function(){ return this._year; }, set:function(){ if(newValue>2004){ this._year=newValue; this.edition+=newValue-2004; } } } });4.如何利用Object.getOwnPropertyDescripter()方法讀取屬性的描述符以讀取屬性的特性
我們可以使用Object.getOwnPropertyDescripter()方法來取得給定屬性的描述符。getOwnPropertyDescripter即為取得自身屬性描述符的意思。這個方法接收兩個參數(shù):屬性所在的對象要要讀取其描述符的屬性名稱。返回一個對象。
對于訪問器屬性而言,這個對象的屬性有configurable、enumerable、get和set;
對于數(shù)據(jù)屬性而言,這個對象的屬性有configurable、enumerable、writable和value。
var book={}; Object.defineProperties(book,{ _year:{ value:2004 }, edition:{ value:1 }, year:{ get:function(){ return this._year; }, set:function(){ if(newValue>2004){ this._year=newValue; this.edition+=newValue-2004; } } } }); var descriptor=Object.getOwnPropertyDescriptor(book,"_year"); console.log(descriptor.value);//2004 console.log(descriptor.configurable);//false 因為通過Object.defineProperties()方法創(chuàng)建的屬性的特性configurable enumerable都是false console.log(typeof descriptor.get);//undefined 注意:這是數(shù)據(jù)屬性,是不具有get特性的 var descriptor=Object.getOwnPropertyDescriptor(book,"year"); console.log(descriptor.value);//undefined console.log(descriptor.enumerable);//false console.log(typeof descriptor.get);//function get雖然是屬性的一個特性,但是它也是函數(shù)。
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://systransis.cn/yun/102070.html
摘要:理解的函數(shù)基礎要搞好深入淺出原型使用原型模型,雖然這經(jīng)常被當作缺點提及,但是只要善于運用,其實基于原型的繼承模型比傳統(tǒng)的類繼承還要強大。中文指南基本操作指南二繼續(xù)熟悉的幾對方法,包括,,。商業(yè)轉載請聯(lián)系作者獲得授權,非商業(yè)轉載請注明出處。 怎樣使用 this 因為本人屬于偽前端,因此文中只看懂了 8 成左右,希望能夠給大家?guī)韼椭?...(據(jù)說是阿里的前端妹子寫的) this 的值到底...
摘要:返回值被傳遞給函數(shù)的對象。描述該方法允許精確添加或修改對象的屬性。描述符必須是兩種形式之一不能同時是兩者??梢允侨魏斡行У闹禂?shù)值,對象,函數(shù)等。該方法返回值被用作屬性值。該方法將接受唯一參數(shù),并將該參數(shù)的新值分配給該屬性。 Object.defineProperties() Object.defineProperty() 方法會直接在一個對象上定義一個新屬性,或者修改一個對象的現(xiàn)有屬性...
摘要:函數(shù)是對象理解函數(shù)是對象,是準確理解函數(shù)的第一步。在中,函數(shù)對象和其他對象一樣,均被視為一等公民。當函數(shù)執(zhí)行完畢,其執(zhí)行環(huán)境從棧中彈出并銷毀。此時的函數(shù)充當構造器的角色。調(diào)用函數(shù)對象的方法并將結果賦給。 函數(shù)是javascript中最重要的內(nèi)容,也是其相對其他語言來說在設計上比較有意思的地方。javascript許多高級特性也或多或少和函數(shù)相關。本文將以函數(shù)為中心,對函數(shù)的各個關鍵知識...
摘要:設計模式是以面向對象編程為基礎的,的面向對象編程和傳統(tǒng)的的面向對象編程有些差別,這讓我一開始接觸的時候感到十分痛苦,但是這只能靠自己慢慢積累慢慢思考。想繼續(xù)了解設計模式必須要先搞懂面向對象編程,否則只會讓你自己更痛苦。 JavaScript 中的構造函數(shù) 學習總結。知識只有分享才有存在的意義。 是時候替換你的 for 循環(huán)大法了~ 《小分享》JavaScript中數(shù)組的那些迭代方法~ ...
摘要:原型中聲明的屬性和對象自帶的屬性原型中聲明的屬性和對象自帶的屬性其實這些屬性也是在原型中的可以認為是帶有特性的,無法被刪除。注意內(nèi)置對象的一些屬性擁有內(nèi)部屬性,因此不能被刪除特殊的變量活化對象的屬性擁有任何函數(shù)實例的返回形參長度屬性也擁有。 http://bubkoo.com/2014/01/23/... 原型中聲明的屬性和對象自帶的屬性 ==原型 prototype 中聲明的屬性和對...
閱讀 3937·2021-09-23 11:51
閱讀 3093·2021-09-22 15:59
閱讀 899·2021-09-09 11:37
閱讀 2096·2021-09-08 09:45
閱讀 1289·2019-08-30 15:54
閱讀 2088·2019-08-30 15:53
閱讀 515·2019-08-29 12:12
閱讀 3318·2019-08-29 11:15