摘要:關(guān)于有人說(shuō)我用刪除這個(gè)屬性不就好了之后打印發(fā)現(xiàn)它還是一只哈士奇。如下的解釋如下操作符會(huì)從某個(gè)對(duì)象上移除指定屬性。
javascript-Object-Property
? javascript-對(duì)象的屬性的延伸學(xué)習(xí)
前言在學(xué)習(xí)vue數(shù)據(jù)綁定的較底層原理時(shí),被setter和getter困惑了很久,一路追根溯源,通過(guò)閱讀《你不知道的javascript》和紅寶書(shū)理解了迷惑我的setter、getter。
首先了解什么是屬性描述符[](http://xurenjie.cn:3000/img/d...
在ES5之前,javascript語(yǔ)言沒(méi)有提供可以檢驗(yàn)屬性特性的方法,是否只讀?不知道;是否可配置?不知道;是否能用for in枚舉?不知道。
ES5之后就有了如下的屬性描述符:
var Dogger = { breed: "柴犬" } Object.getOwnPropertyDescriptor( Dogger , "breed" );
輸出:
{ value: "柴犬", writable: true, configurable: true, enumerable: true }
在這,創(chuàng)建了一個(gè)品種為柴犬的dogger。[[Value]]特性將設(shè)置為"柴犬",之后操作對(duì)breed的任何修改將反映到這個(gè)位置。對(duì),沒(méi)錯(cuò),這個(gè)getOwnPropertyDescriptor( Dogger , "breed" )函數(shù)就是我們要的檢驗(yàn)屬性特性的方法。
默認(rèn):在創(chuàng)建普通對(duì)象屬性時(shí),屬性描述符會(huì)使用默認(rèn)值,即可寫(xiě)可配可枚舉。(都為true)
下面分別介紹一下、這幾個(gè)屬性
writeable決定是否修改屬性的值,是否可以指定新的值給它
Dogger.breed = "哈士奇"
很好理解,當(dāng)writeable為false的時(shí)候,其實(shí)定義了一個(gè)空的setter(等會(huì)會(huì)提),這個(gè)操作將無(wú)效,在嚴(yán)格模式下會(huì)拋出一個(gè)TypeError的錯(cuò)誤。
configurable與configurable緊密相連的就是defineProperty( )這個(gè)方法了,當(dāng)configurable: false 將不可使用‘好基友’defineProperty( )來(lái)配置。后面還會(huì)介紹一個(gè)會(huì)受影響的delete。
var Dogger = { breed: "柴犬" } Object.defineProperty( Dogger, "breed", { value: "哈士奇", writable: true, configurable: false, enumerable: true } ) Dogger.breed // "哈士奇" | 哈哈!我變成了一只哈士奇 Object.defineProperty( Dogger, "breed", { value: "柴犬", writable: true, configurable: true, enumerable: true } ) // TypeError
這只作死的柴犬在通過(guò)defineProperty( )把自己配置成哈士奇之后,順便把configurable修改為false,這樣之后defineProperty( )不管是否嚴(yán)格模式都將報(bào)TypeError的錯(cuò)誤,這是單向操作,無(wú)法撤銷。 一失足成千古恨~
[](http://xurenjie.cn:3000/img/d...
還是可以通過(guò)writable的方式修改breed的嘛~,不過(guò)這里有一個(gè)方法可以讓dogger徹底絕望,使breed無(wú)法修改,也就是這個(gè)例外:這個(gè)時(shí)候defineProperty( )還是可以使用的(如下),只可以修改writable,configurable需要與剛才的false一致。
Object.defineProperty( Dogger, "breed", { value: "哈士奇", writable: false, configurable: false, enumerable: true } )
這樣之后柴犬永遠(yuǎn)變成了只哈士奇。
[](http://xurenjie.cn:3000/img/d...
有人說(shuō)我用delete刪除這個(gè)breed屬性不就好了?
delete Dogger.breed
之后打印dogger發(fā)現(xiàn)它還是一只哈士奇。如下:
MDN的解釋如下
delete 操作符會(huì)從某個(gè)對(duì)象上移除指定屬性。成功刪除的時(shí)候回返回 true,否則返回 false。
Non-configurable properties cannot be removed. This includes properties ofbuilt-in objects like Math, Array, Object and properties that are created as non-configurable with methods like Object.defineProperty( ).
When in strict mode, if delete is used on a direct reference to a variable, a function argument or a function name, it will throw a SyntaxError.
Any variable defined with var is marked as non-configurable. In the following example, salary is non-configurable and cannot be deleted. In non-strict mode, the delete operation will return false.
delete只是用來(lái)直接刪除對(duì)象(可刪除的)屬性,當(dāng)breed屬性是Dogger的最后引用者,對(duì)這個(gè)屬性執(zhí)行delete操作,這個(gè)為引用的對(duì)象就可以被垃圾回收了,不要看成一個(gè)釋放內(nèi)存的工具,而是刪除屬性的操作,僅此。
enumerable當(dāng)且僅當(dāng)該屬性的 enumerable 為 true 時(shí),該屬性才能夠出現(xiàn)在對(duì)象的枚舉屬性中。默認(rèn)為 false。
屬性特性 enumerable 定義了對(duì)象的屬性是否可以在 for...in 循環(huán)和 Object.keys( ) 中被枚舉。
放上MDN的代碼片段:
[ [ Get ] ]和[ [ Put ] ] [ [ Get ] ]var o = {};
Object.defineProperty(o, "a", { value : 1, enumerable:true });
Object.defineProperty(o, "b", { value : 2, enumerable:false });
Object.defineProperty(o, "c", { value : 3 }); // enumerable defaults to false
o.d = 4; // 如果使用直接賦值的方式創(chuàng)建對(duì)象的屬性,則這個(gè)屬性的enumerable為truefor (var i in o) {
console.log(i);
}
// 打印 "a" 和 "d" (in undefined order)Object.keys(o); // ["a", "d"]
o.propertyIsEnumerable("a"); // true
o.propertyIsEnumerable("b"); // false
o.propertyIsEnumerable("c"); // false
Dogger.breed
如上,對(duì)一個(gè)對(duì)象進(jìn)行訪問(wèn)時(shí)有一個(gè)很重要的細(xì)節(jié)。Dogger.breed是一次屬性訪問(wèn),但并不是僅僅在Dogger中查找breed,其實(shí)看起來(lái)更像是在語(yǔ)言規(guī)范中執(zhí)行了Dogger的[ [ Get ] ]操作,看上去像[ [ Get ] ]( )。
在對(duì)象中查找有沒(méi)有這個(gè)屬性。
在該對(duì)象的原型鏈上查找有沒(méi)有這個(gè)屬性。
都沒(méi)找到返回undefined(注意:如果那個(gè)屬性值恰好為undefined時(shí),雖然返回值一樣,但是底層發(fā)生的事是不一樣的)
[ [ Put ] ][ [ Get ] ]對(duì)應(yīng)[ [ Put ] ]操作,一旦給對(duì)象屬性賦值就觸發(fā)設(shè)置和創(chuàng)建這個(gè)屬性發(fā)生的事情是這樣的:
首先確定是否存在這個(gè)屬性。breed是否存在
存在,是否是setter。是setter就調(diào)用setter,是否是setter來(lái)給breed賦值
writable是否為false,false則無(wú)效。breed的writable是否為false
設(shè)置值為該屬性的值
Getter和Setter在《 javascript高級(jí)程序設(shè)計(jì) 》中成為訪問(wèn)器屬性,也稱為訪問(wèn)描述符,getter和setter是兩個(gè)隱形的函數(shù),getter為讀取屬性值的函數(shù),setter為設(shè)置屬性值的函數(shù),在訪問(wèn)這個(gè)階段我們關(guān)注的是四個(gè)屬性:
set
get
configurable
enumerable
這時(shí)候我們用Dogger的例子來(lái)了解一下這些特性
var Dogger = { get breed() { ? ? ? ?return "柴犬" ? ?} } Object.defineProperty( Dogger "breed-type", { get: function() { ? ? ?return this.breed + "品種" } } ) Dogger.breed // "柴犬" Dogger.breed-type // "柴犬品種"
沒(méi)毛病,不管是隱式調(diào)用還是顯式確實(shí)能夠讓我們定義屬性,自動(dòng)調(diào)用隱藏函數(shù),返回值為屬性訪問(wèn)的返回值
[](http://xurenjie.cn:3000/img/d...
如果這時(shí)候,我們想用賦值操作給Dogger改變屬性會(huì)怎么樣?
Dogger.breed = "哈士奇" Dogger.breed // "柴犬"
由于只定義了breed的getter,所以對(duì)它的值進(jìn)行設(shè)置時(shí)set操作會(huì)忽略賦值操作(也不會(huì)報(bào)錯(cuò))。其實(shí)就算定義了setter,自定義
的getter還是只會(huì)返回getter設(shè)置的值。
因此你去改變屬性的值時(shí),你還需要定義一個(gè)setter,通常來(lái)說(shuō),他們是成雙成對(duì)的。不寫(xiě)嚴(yán)格模式會(huì)報(bào)錯(cuò)。
setter其實(shí)就是我們最常用的賦值操作
var Dogger = { get breed() { ? ? ? ?return "柴犬" ? ?} set breed(val) { ? ? ? ?this._breed_ = val ? ?} } Dogger.breed = "哈士奇" Dogger.breed // "哈士奇"
這樣一來(lái),賦值操作就可以改變啦!我們把賦值操作存儲(chǔ)給新建的_breed_ ,只是一種慣例,通過(guò)setter可以改變對(duì)變量訪問(wèn)值的處理規(guī)則。
如果不用_breed_,setter/getter的調(diào)用執(zhí)行時(shí)機(jī)class Dogger { constructor (name, breed) { this.name = name; this.breed = breed; } set breed (breed) { console.log("setter"); this.breed = breed; } get breed () { console.log("getter"); return this.breed; } } var dogger = new Dogger("忠犬八公", "柴犬");
代碼報(bào)錯(cuò)了!!!這是因?yàn)椋跇?gòu)造函數(shù)中執(zhí)行this.breed = breed的時(shí)候,就會(huì)去調(diào)用set breed,在set breed方法中,我們又執(zhí)行this.breed = breed,進(jìn)行無(wú)限遞歸,最后導(dǎo)致棧溢出(RangeError)。
因此,原來(lái)只要this.breed中的屬性名和set breed/get breed后面的breed一致,對(duì)this.breed就會(huì)調(diào)用setter/getter,也就是說(shuō)setter/getter是hook函數(shù),而真實(shí)的存儲(chǔ)變量是_breed_,我們可以在代碼中直接獲取它。
ES6 的 proxyProxy可以理解成代理代辦,在目標(biāo)對(duì)象之前架設(shè)一層“攔截”,劫持了外界對(duì)該對(duì)象的訪問(wèn)和設(shè)置(setter和getter)。
借用最近看到的例子直接看代碼吧
const phoneHandler = { get (target,name) { console.log(`正在讀取${name}`) //"0102101220".replace(/(d{3})(d{3})(d{4})/,"$1-$2-$3") //"010-210-1220" return target[name].replace(/([0-9]{3})(d{3})(d{4})/,"($1)-$2-$3") }, set (target, name, value) { console.log(`正在設(shè)置${name}`) // .match正則表達(dá)式的方法:匹配所有數(shù)字,全局匹配 target[name] = value.match(/[0-9]/g).join("") } } // 攔截對(duì)象,代理代辦,對(duì)空對(duì)象的代理 // 復(fù)雜對(duì)象 ajax 將代碼放在proxy中 const phoneNumber = new Proxy({}, phoneHandler) phoneNumber.phone = "電話:0102101220" console.log(phoneNumber.phone)
不難看出new出來(lái)的Proxy是對(duì)空對(duì)象的代理,這樣一來(lái),setter和getter都被phoneHandler中的set和get包辦了,用于復(fù)雜對(duì)象, ajax, 將代碼放在proxy中代理。
參考你不知道的javascript
javascript高級(jí)程序設(shè)計(jì)
求star:https://github.com/renjie1996...
qq:2578370399
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/82999.html
摘要:在模板中放入太多的邏輯會(huì)讓模板過(guò)重且難以維護(hù)。它會(huì)根據(jù)控件類型自動(dòng)選取正確的方法來(lái)更新元素。指令需要使用的語(yǔ)法,指的是原數(shù)據(jù)數(shù)組,指的是迭代的數(shù)組元素。 注:本教程所使用的vue版本為 2.5.16 MVC與MVVM MVC(Model-View-Controller): M指的是從后臺(tái)獲取到的數(shù)據(jù), V指的是顯示動(dòng)態(tài)數(shù)據(jù)的html頁(yè)面, C是指響應(yīng)用戶操作、經(jīng)過(guò)業(yè)務(wù)邏輯處理后去更新...
摘要:在生成的項(xiàng)目中,我們打開(kāi)文件夾下組件,為便于演示,刪減了一部分內(nèi)容本文中的例子都將改造組件來(lái)演示語(yǔ)法一創(chuàng)建組件在中,有好幾種方式用來(lái)創(chuàng)建組件,后面會(huì)單獨(dú)寫(xiě)一篇文章來(lái)介紹。表達(dá)式插值中也支持表達(dá)式插值用雙大括號(hào)將表達(dá)式括起來(lái)。 Vue 的官方文檔寫(xiě)的非常棒(另一個(gè)我覺(jué)得中文文檔寫(xiě)的很好地是 Ant-Design)。 這篇文章以使用 vue-cli 生成的項(xiàng)目為基礎(chǔ),以完整 demo 的...
摘要:指令帶有前綴,以表示它們是提供的特殊屬性。最后,我們需要為賦值世界舞王尼古拉斯趙四世界舞王尼古拉斯趙四初學(xué)就到這里了,相信你已經(jīng)在腦子里確定了的原理的概念也已經(jīng)非常清楚了,希望你能夠在學(xué)習(xí)的道路上越走越遠(yuǎn),最后感謝你的瀏覽。 vue.js vue介紹 Vue.js(讀音 /vju?/,類似于 view) 是一套構(gòu)建用戶界面的漸進(jìn)式框架。與其他重量級(jí)框架不同的是,Vue 采用自底向上增量...
摘要:如果我們作為一個(gè)后端開(kāi)發(fā)者想掌握一個(gè)前端框架,是一個(gè)好選擇,因?yàn)樗銐虻囊讓W(xué)。是語(yǔ)言的下一代標(biāo)準(zhǔn)。數(shù)據(jù)方法生命周期鉤子函數(shù)其他有些內(nèi)容比較重要,留到后面講定義數(shù)據(jù)定義數(shù)據(jù)定義了數(shù)據(jù),那么就可以在管理的區(qū)域中使用的獲取數(shù)據(jù)的語(yǔ)法來(lái)獲取數(shù)據(jù)。目錄 前言: iview組件庫(kù)示例 element組件庫(kù)示例 ...
摘要:當(dāng)我們的視圖和數(shù)據(jù)任何一方發(fā)生變化的時(shí)候,我們希望能夠通知對(duì)方也更新,這就是所謂的數(shù)據(jù)雙向綁定。返回值返回傳入函數(shù)的對(duì)象,即第一個(gè)參數(shù)該方法重點(diǎn)是描述,對(duì)象里目前存在的屬性描述符有兩種主要形式數(shù)據(jù)描述符和存取描述符。 前言 談起當(dāng)前前端最熱門的 js 框架,必少不了 Vue、React、Angular,對(duì)于大多數(shù)人來(lái)說(shuō),我們更多的是在使用框架,對(duì)于框架解決痛點(diǎn)背后使用的基本原理往往關(guān)注...
閱讀 4933·2021-11-25 09:43
閱讀 1186·2021-11-24 09:38
閱讀 1892·2021-09-30 09:54
閱讀 2799·2021-09-23 11:21
閱讀 2366·2021-09-10 10:51
閱讀 2368·2021-09-03 10:45
閱讀 1163·2019-08-30 15:52
閱讀 1765·2019-08-30 14:13