




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
第JavaScriptdefineProperty如何實現(xiàn)屬性劫持目錄前言描述符
細說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
當然尋常的例子,我們是不會這么玩的,太啰嗦了。
但defineProperty可以更精確地添加或修改對象的屬性。
描述符
先說個專有名詞:描述符。
其實就是defineProperty的第三個參數(shù),是個對象。這個對象的有以下屬性:
configurable屬性:能不能修改描述符,就是能不能再次修改描述符的其他屬性
enumerable屬性:能不能枚舉該屬性,就是a屬性能不能被for到
writable屬性:能不能修改屬性值,就是能不能這樣修改obj.a=1
value屬性:該屬性的值
get屬性:是個函數(shù),當訪問該屬性的時候,函數(shù)自動調(diào)用,函數(shù)返回值就是該屬性的值
set屬性:是個函數(shù),當修改該屬性的時候,函數(shù)自動調(diào)用,函數(shù)有且只有一個參數(shù),賦值的新值
注意?。?!
描述符里的value屬性writable屬性與get屬性set屬性是互斥的關(guān)系,只能存在一個
另外的屬性默認值都是false,不想false的話,記得配置哈,不細說(主要我也不怎么用)。
細說get和set
get屬性:是個函數(shù),當訪問該屬性的時候,函數(shù)自動調(diào)用,函數(shù)返回值就是該屬性的值
set屬性:是個函數(shù),當修改該屬性的時候,函數(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;
劫持對象的所有屬性-包括對象類型的屬性值
上面的有個缺陷,就是當屬性值也是對象的時候,不能劫持屬性值,如{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)測對象刪除屬性
不能劫持數(shù)組的修改
當然數(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上
相當于,用defineProperty,在options上增加新屬性:
//先掛載單個屬性
//options.data相當于sourceoptions相當于target
functionproxyKey(target,source,key){
Object.defineProperty(target,key,{
//這里的source[key]相當于變量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)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- ××超市版權(quán)合規(guī)制度
- 2025年德語TestDaF口語模擬試卷:歷年真題解析與備考策略
- 2025年電工特種作業(yè)操作證考試試卷(電氣設(shè)備操作安全)
- 2025年春季全國英語等級考試(PETS)四級試卷含聽力與寫作篇
- 2025年BIM技術(shù)在工程項目施工質(zhì)量控制中的應(yīng)用報告001
- 建筑施工安全管理信息化在施工現(xiàn)場安全防護設(shè)施改進研究報告
- 人力資源分析報告
- 美妝行業(yè)個性化定制服務(wù)模式下的美妝產(chǎn)品定制流程研究報告
- 傳統(tǒng)食品工業(yè)2025年環(huán)保型生產(chǎn)技術(shù)改造與市場前景研究報告
- 2025年康復(fù)醫(yī)療服務(wù)體系康復(fù)康復(fù)服務(wù)康復(fù)康復(fù)創(chuàng)新與運營模式研究報告
- 心絞痛培訓(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é)院
- 國家開放大學(xué)??啤渡鐣{(diào)查研究與方法》期末紙質(zhì)考試總題庫2025春期考試版
- 2024年設(shè)備監(jiān)理師考試題庫及答案(歷年真題)
- 財務(wù)指標分析培訓(xùn)課件
評論
0/150
提交評論