




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
第JavaScriptdefineProperty如何實現(xiàn)屬性劫持目錄前言描述符
細(xì)說get和set劫持對象的某個屬性
劫持對象的所有屬性
劫持對象的所有屬性-包括對象類型的屬性值
defineProperty的缺陷defineProperty還可以掛載屬性
defineProperty還能寫日志
總結(jié)
前言
defineProperty是vue實現(xiàn)數(shù)據(jù)劫持的核心,本文一點點的說明defineProperty怎么實現(xiàn)屬性劫持的。
其實我們一般的操作對象屬性的方式,增加或者修改屬性,均可以使用Object.defineProperty。
letobj={};
//尋常操作:增加/修改新屬性
obj.a=1;
//等同于:
Object.defineProperty(o,"a",{
value:1,
writable:true,
configurable:true,
enumerable:true
當(dāng)然尋常的例子,我們是不會這么玩的,太啰嗦了。
但defineProperty可以更精確地添加或修改對象的屬性。
描述符
先說個專有名詞:描述符。
其實就是defineProperty的第三個參數(shù),是個對象。這個對象的有以下屬性:
configurable屬性:能不能修改描述符,就是能不能再次修改描述符的其他屬性
enumerable屬性:能不能枚舉該屬性,就是a屬性能不能被for到
writable屬性:能不能修改屬性值,就是能不能這樣修改obj.a=1
value屬性:該屬性的值
get屬性:是個函數(shù),當(dāng)訪問該屬性的時候,函數(shù)自動調(diào)用,函數(shù)返回值就是該屬性的值
set屬性:是個函數(shù),當(dāng)修改該屬性的時候,函數(shù)自動調(diào)用,函數(shù)有且只有一個參數(shù),賦值的新值
注意!??!
描述符里的value屬性writable屬性與get屬性set屬性是互斥的關(guān)系,只能存在一個
另外的屬性默認(rèn)值都是false,不想false的話,記得配置哈,不細(xì)說(主要我也不怎么用)。
細(xì)說get和set
get屬性:是個函數(shù),當(dāng)訪問該屬性的時候,函數(shù)自動調(diào)用,函數(shù)返回值就是該屬性的值
set屬性:是個函數(shù),當(dāng)修改該屬性的時候,函數(shù)自動調(diào)用,函數(shù)有且只有一個參數(shù),賦值的新值
默念三遍,背誦。
寫個get和set的例子輔助理解。
這個例子必須掌握,弄懂之后基本就掌握了數(shù)據(jù)劫持的精髓了
letobj={};
letvalue=1;
Object.defineProperty(obj,"b",{
get(){
console.log("讀取b屬性",value);
returnvalue;
set(newValue){
console.log("設(shè)置b屬性",newValue);
value=newValue;
//觸發(fā)get函數(shù),get的返回值就是屬性值
console.log(obj.b);
//觸發(fā)set函數(shù),value的值變成了2,注意?。?!,此時內(nèi)存里,屬性值并沒有改變
obj.b=2;
//但是,想要讀取屬性值的時候,就必然會觸發(fā)get函數(shù),屬性值也自然就改變了,這個思想真的很贊
console.log(obj.b);
這里有個坑:get里是不能有讀取的操作,不然一直死循環(huán),所以使用到getset的地方,總需要借助一個變量
所以,這里,變量value的值就是屬性的值,如果想要修改屬性,修改value的值即可。
這個例子弄懂了,get,set的精髓,我覺得也就差不多了。
劫持對象的某個屬性
有了剛剛例子的基礎(chǔ),試著寫寫劫持對象的任意一個屬性。
functionobserveKey(obj,key){
letvalue=obj[key];
Object.defineProperty(obj,key,{
get(){
console.log("讀取屬性",value);
returnvalue;
set(newValue){
console.log("設(shè)置屬性",newValue);
value=newValue;
letobj={a:1};
observeKey(obj,"a");
//讀取a,觸發(fā)get函數(shù)
console.log(obj.a);
//設(shè)置a,觸發(fā)set函數(shù)
obj.a=1;
劫持對象的所有屬性
再試試劫持對象的所有屬性
其實就是遍歷:
functionobserveObj(obj){
for(letkeyinobj){
//直接使用obj.hasOwnProperty會提示不規(guī)范
if(Ototype.hasOwnProperty.call(obj,key)){
observeKey(obj,key);
returnobj;
functionobserveKey(obj,key){
letvalue=obj[key];
Object.defineProperty(obj,key,{
get(){
console.log("讀取屬性",value);
returnvalue;
set(newValue){
console.log("設(shè)置屬性",newValue);
value=newValue;
letobj={a:1,b:2};
observeObj(obj);
console.log(obj);
//讀取a,觸發(fā)get函數(shù)
console.log(obj.a);
//設(shè)置a,觸發(fā)set函數(shù)
obj.a=1;
劫持對象的所有屬性-包括對象類型的屬性值
上面的有個缺陷,就是當(dāng)屬性值也是對象的時候,不能劫持屬性值,如{a:1,c:{b:1}}
簡單,遞歸,補上就行。
functionobserveObj(obj){
//加上參數(shù)限制,必須是對象才有劫持,也是遞歸的終止條件
if(typeofobj!=="object"||obj==null){
return;
for(letkeyinobj){
//直接使用obj.hasOwnProperty會提示不規(guī)范
if(Ototype.hasOwnProperty.call(obj,key)){
observeKey(obj,key);
//這里劫持該屬性的屬性值,如果不是對象直接返回,不影響
observeObj(obj[key]);
returnobj;
functionobserveKey(obj,key){
letvalue=obj[key];
Object.defineProperty(obj,key,{
get(){
console.log("讀取屬性",value);
returnvalue;
set(newValue){
console.log("設(shè)置屬性",newValue);
value=newValue;
letobj={a:1,b:2,c:{name:"c"}};
observeObj(obj);
console.log(obj);
//讀取a,觸發(fā)get函數(shù)
console.log(obj.a);
//設(shè)置a,觸發(fā)set函數(shù)
obj.a=1;
//觸發(fā)set函數(shù)
="d";
注意,observeObj這個函數(shù),不能劫持對象的新增屬性,只能劫持對象已有的屬性。
defineProperty的缺陷
不能監(jiān)測對象增加屬性
不能監(jiān)測對象刪除屬性
不能劫持?jǐn)?shù)組的修改
當(dāng)然數(shù)組的修改可以通過別的方式監(jiān)測到的,其是通過劫持改變數(shù)組方法實現(xiàn)的。
以上缺陷,也是vue里面為啥有$set/$delete以及對數(shù)組只能使用特定方法才能檢測到。
letobj={a:1,b:[1,2]};
observeObj(obj);
//新增屬性
obj.c=3;
//不會觸發(fā)get函數(shù)
console.log(obj.c);
//不會觸發(fā)set函數(shù)
obj.b.push(3);
defineProperty還可以掛載屬性
其實就是訪問可以簡寫成,專業(yè)話術(shù),將data上的屬性掛載到options上
相當(dāng)于,用defineProperty,在options上增加新屬性:
//先掛載單個屬性
//options.data相當(dāng)于sourceoptions相當(dāng)于target
functionproxyKey(target,source,key){
Object.defineProperty(target,key,{
//這里的source[key]相當(dāng)于變量value,所以說最簡單的那個例子是核心
get(){
returnsource[key];
set(newValue){
if(newValue===source[key]){
return;
source[key]=newValue;
//遍歷屬性,掛載下
functionproxyObj(target,source){
for(letkeyinsource){
//直接使用obj.hasOwnProperty會提示不規(guī)范
if(Ototype.hasOwnProperty.call(source,key)){
proxyKey(target,source,key);
letoptions={
data:{name:1}
proxyObj(options,options.data);
console.log();
話說,vue的屬性劫持和掛載屬性,核心原理差不多就是上面這些。
defineProperty還能寫日志
比如obj有個屬性,此屬性值經(jīng)常變化,想要記錄其所有變化的值,以此可以形成日志。
letobj={a:1};
letlog=[obj.a];
letvalue=obj.a;
Object.defineProperty(obj,"a",{
get(){
returnvalue;
set(newValue){
if(newValue===value){
return;
value=newValue;
log.push(newValue);
obj.a=2;
obj.a=3;
obj.a=4;
//[1,2,3,4]
console.log(log);
通用的可以抽離出一個類,專門記錄某個值的變化
classArchiver{
constructor(){
letvalue=null;
this.archive=[];
Object.defineProperty(this,"a",{
get(){
retu
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 線上線下融合商城企業(yè)制定與實施新質(zhì)生產(chǎn)力項目商業(yè)計劃書
- 超市內(nèi)烹飪課程與工作坊行業(yè)深度調(diào)研及發(fā)展項目商業(yè)計劃書
- 私人島嶼租賃服務(wù)行業(yè)跨境出海項目商業(yè)計劃書
- 醫(yī)療虛擬現(xiàn)實培訓(xùn)行業(yè)跨境出海項目商業(yè)計劃書
- 醫(yī)藥合同外包服務(wù)(CRO)行業(yè)跨境出海項目商業(yè)計劃書
- 教科版五年級科學(xué)上冊課題研究計劃
- 化工項目分包計劃和管理措施
- 2025年公務(wù)員考試時事政治模擬試題附答案詳解【b卷】
- 2025年公務(wù)員考試時事政治模擬試題含答案詳解【培優(yōu)b卷】
- 北師大版一年級數(shù)學(xué)上冊階段復(fù)習(xí)計劃
- 初中體育《足球腳內(nèi)側(cè)運球》課件大綱
- 青海省西寧市2025屆九年級下學(xué)期中考一模地理試卷(含答案)
- 2023+ESC急性冠狀動脈綜合征管理指南解讀 課件
- 心絞痛培訓(xùn)課件
- 保險行業(yè)發(fā)展趨勢和機遇
- 注塑加工廠管理
- 邊坡作業(yè)安全教育培訓(xùn)
- 《2025年CSCO腎癌診療指南》解讀
- 小學(xué)語文跨學(xué)科主題學(xué)習(xí)策略研究
- 2022-2023學(xué)年浙江省溫州市永嘉縣人教PEP版四年級下冊期末測試英語試卷
- 東盟經(jīng)貿(mào)文化與習(xí)俗知到智慧樹章節(jié)測試課后答案2024年秋海南外國語職業(yè)學(xué)院
評論
0/150
提交評論