JavaScript defineProperty如何實(shí)現(xiàn)屬性劫持_第1頁
JavaScript defineProperty如何實(shí)現(xiàn)屬性劫持_第2頁
JavaScript defineProperty如何實(shí)現(xiàn)屬性劫持_第3頁
JavaScript defineProperty如何實(shí)現(xiàn)屬性劫持_第4頁
JavaScript defineProperty如何實(shí)現(xiàn)屬性劫持_第5頁
已閱讀5頁,還剩6頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第JavaScriptdefineProperty如何實(shí)現(xiàn)屬性劫持目錄前言描述符

細(xì)說get和set劫持對(duì)象的某個(gè)屬性

劫持對(duì)象的所有屬性

劫持對(duì)象的所有屬性-包括對(duì)象類型的屬性值

defineProperty的缺陷defineProperty還可以掛載屬性

defineProperty還能寫日志

總結(jié)

前言

defineProperty是vue實(shí)現(xiàn)數(shù)據(jù)劫持的核心,本文一點(diǎn)點(diǎn)的說明defineProperty怎么實(shí)現(xiàn)屬性劫持的。

其實(shí)我們一般的操作對(duì)象屬性的方式,增加或者修改屬性,均可以使用Object.defineProperty。

letobj={};

//尋常操作:增加/修改新屬性

obj.a=1;

//等同于:

Object.defineProperty(o,"a",{

value:1,

writable:true,

configurable:true,

enumerable:true

當(dāng)然尋常的例子,我們是不會(huì)這么玩的,太啰嗦了。

但defineProperty可以更精確地添加或修改對(duì)象的屬性。

描述符

先說個(gè)專有名詞:描述符。

其實(shí)就是defineProperty的第三個(gè)參數(shù),是個(gè)對(duì)象。這個(gè)對(duì)象的有以下屬性:

configurable屬性:能不能修改描述符,就是能不能再次修改描述符的其他屬性

enumerable屬性:能不能枚舉該屬性,就是a屬性能不能被for到

writable屬性:能不能修改屬性值,就是能不能這樣修改obj.a=1

value屬性:該屬性的值

get屬性:是個(gè)函數(shù),當(dāng)訪問該屬性的時(shí)候,函數(shù)自動(dòng)調(diào)用,函數(shù)返回值就是該屬性的值

set屬性:是個(gè)函數(shù),當(dāng)修改該屬性的時(shí)候,函數(shù)自動(dòng)調(diào)用,函數(shù)有且只有一個(gè)參數(shù),賦值的新值

注意?。。?/p>

描述符里的value屬性writable屬性與get屬性set屬性是互斥的關(guān)系,只能存在一個(gè)

另外的屬性默認(rèn)值都是false,不想false的話,記得配置哈,不細(xì)說(主要我也不怎么用)。

細(xì)說get和set

get屬性:是個(gè)函數(shù),當(dāng)訪問該屬性的時(shí)候,函數(shù)自動(dòng)調(diào)用,函數(shù)返回值就是該屬性的值

set屬性:是個(gè)函數(shù),當(dāng)修改該屬性的時(shí)候,函數(shù)自動(dòng)調(diào)用,函數(shù)有且只有一個(gè)參數(shù),賦值的新值

默念三遍,背誦。

寫個(gè)get和set的例子輔助理解。

這個(gè)例子必須掌握,弄懂之后基本就掌握了數(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,注意!??!,此時(shí)內(nèi)存里,屬性值并沒有改變

obj.b=2;

//但是,想要讀取屬性值的時(shí)候,就必然會(huì)觸發(fā)get函數(shù),屬性值也自然就改變了,這個(gè)思想真的很贊

console.log(obj.b);

這里有個(gè)坑:get里是不能有讀取的操作,不然一直死循環(huán),所以使用到getset的地方,總需要借助一個(gè)變量

所以,這里,變量value的值就是屬性的值,如果想要修改屬性,修改value的值即可。

這個(gè)例子弄懂了,get,set的精髓,我覺得也就差不多了。

劫持對(duì)象的某個(gè)屬性

有了剛剛例子的基礎(chǔ),試著寫寫劫持對(duì)象的任意一個(gè)屬性。

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;

劫持對(duì)象的所有屬性

再試試劫持對(duì)象的所有屬性

其實(shí)就是遍歷:

functionobserveObj(obj){

for(letkeyinobj){

//直接使用obj.hasOwnProperty會(huì)提示不規(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;

劫持對(duì)象的所有屬性-包括對(duì)象類型的屬性值

上面的有個(gè)缺陷,就是當(dāng)屬性值也是對(duì)象的時(shí)候,不能劫持屬性值,如{a:1,c:{b:1}}

簡(jiǎn)單,遞歸,補(bǔ)上就行。

functionobserveObj(obj){

//加上參數(shù)限制,必須是對(duì)象才有劫持,也是遞歸的終止條件

if(typeofobj!=="object"||obj==null){

return;

for(letkeyinobj){

//直接使用obj.hasOwnProperty會(huì)提示不規(guī)范

if(Ototype.hasOwnProperty.call(obj,key)){

observeKey(obj,key);

//這里劫持該屬性的屬性值,如果不是對(duì)象直接返回,不影響

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這個(gè)函數(shù),不能劫持對(duì)象的新增屬性,只能劫持對(duì)象已有的屬性。

defineProperty的缺陷

不能監(jiān)測(cè)對(duì)象增加屬性

不能監(jiān)測(cè)對(duì)象刪除屬性

不能劫持?jǐn)?shù)組的修改

當(dāng)然數(shù)組的修改可以通過別的方式監(jiān)測(cè)到的,其是通過劫持改變數(shù)組方法實(shí)現(xiàn)的。

以上缺陷,也是vue里面為啥有$set/$delete以及對(duì)數(shù)組只能使用特定方法才能檢測(cè)到。

letobj={a:1,b:[1,2]};

observeObj(obj);

//新增屬性

obj.c=3;

//不會(huì)觸發(fā)get函數(shù)

console.log(obj.c);

//不會(huì)觸發(fā)set函數(shù)

obj.b.push(3);

defineProperty還可以掛載屬性

其實(shí)就是訪問可以簡(jiǎn)寫成,專業(yè)話術(shù),將data上的屬性掛載到options上

相當(dāng)于,用defineProperty,在options上增加新屬性:

//先掛載單個(gè)屬性

//options.data相當(dāng)于sourceoptions相當(dāng)于target

functionproxyKey(target,source,key){

Object.defineProperty(target,key,{

//這里的source[key]相當(dāng)于變量value,所以說最簡(jiǎn)單的那個(gè)例子是核心

get(){

returnsource[key];

set(newValue){

if(newValue===source[key]){

return;

source[key]=newValue;

//遍歷屬性,掛載下

functionproxyObj(target,source){

for(letkeyinsource){

//直接使用obj.hasOwnProperty會(huì)提示不規(guī)范

if(Ototype.hasOwnProperty.call(source,key)){

proxyKey(target,source,key);

letoptions={

data:{name:1}

proxyObj(options,options.data);

console.log();

話說,vue的屬性劫持和掛載屬性,核心原理差不多就是上面這些。

defineProperty還能寫日志

比如obj有個(gè)屬性,此屬性值經(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);

通用的可以抽離出一個(gè)類,專門記錄某個(gè)值的變化

classArchiver{

constructor(){

letvalue=null;

this.archive=[];

Object.defineProperty(this,"a",{

get(){

retu

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論