[{"data":1,"prerenderedAt":1220},["ShallowReactive",2],{"page-\u002Fvue\u002Fvue中数组变动监听":3},{"id":4,"title":5,"body":6,"description":1213,"extension":1214,"meta":1215,"navigation":743,"path":1216,"seo":1217,"stem":1218,"__hash__":1219},"content\u002FVue\u002FVue中数组变动监听.md","Vue中数组变动监听",{"type":7,"value":8,"toc":1204},"minimark",[9,13,35,39,54,107,132,192,264,277,696,709,949,952,956,987,1086,1090,1117,1180,1183,1191,1194,1200],[10,11,5],"h1",{"id":12},"vue中数组变动监听",[14,15,16,20,21,24,25,27,28,31,32,34],"p",{},[17,18,19],"code",{},"Vue","的通过数据劫持的方式实现数据的双向绑定，即使用",[17,22,23],{},"Object.defineProperty()","来实现对属性的劫持，但是",[17,26,23],{},"中的",[17,29,30],{},"setter","是无法直接实现数组中值的改变的劫持行为的，想要实现对于数组下标直接访问的劫持需要使用索引对每一个值进行劫持，但是在",[17,33,19],{},"中考虑性能问题并未采用这种方式，所以需要特殊处理数组的变动。",[36,37,38],"h2",{"id":38},"描述",[14,40,41,43,44,46,47,50,51,53],{},[17,42,19],{},"是通过数据劫持的方式来实现数据双向数据绑定的，其中最核心的方法便是通过",[17,45,23],{},"来实现对属性的劫持，该方法允许精确地添加或修改对象的属性，对数据添加属性描述符中的",[17,48,49],{},"getter","与",[17,52,30],{},"存取描述符实现劫持。",[55,56,61],"pre",{"className":57,"code":58,"language":59,"meta":60,"style":60},"language-javascript shiki shiki-themes github-light github-dark","var obj = { __x: 1 };\nObject.defineProperty(obj, \"x\", {\n    set: function(x){ console.log(\"watch\"); this.__x = x; },\n    get: function(){ return this.__x; }\n});\nobj.x = 11; \u002F\u002F watch\nconsole.log(obj.x); \u002F\u002F 11\n","javascript","",[17,62,63,71,77,83,89,95,101],{"__ignoreMap":60},[64,65,68],"span",{"class":66,"line":67},"line",1,[64,69,70],{},"var obj = { __x: 1 };\n",[64,72,74],{"class":66,"line":73},2,[64,75,76],{},"Object.defineProperty(obj, \"x\", {\n",[64,78,80],{"class":66,"line":79},3,[64,81,82],{},"    set: function(x){ console.log(\"watch\"); this.__x = x; },\n",[64,84,86],{"class":66,"line":85},4,[64,87,88],{},"    get: function(){ return this.__x; }\n",[64,90,92],{"class":66,"line":91},5,[64,93,94],{},"});\n",[64,96,98],{"class":66,"line":97},6,[64,99,100],{},"obj.x = 11; \u002F\u002F watch\n",[64,102,104],{"class":66,"line":103},7,[64,105,106],{},"console.log(obj.x); \u002F\u002F 11\n",[14,108,109,110,27,112,114,115,117,118,120,121,124,125,127,128,131],{},"而如果当劫持的值为数组且直接根据下标处理数组中的值时，",[17,111,23],{},[17,113,30],{},"是无法直接实现数组中值的改变的劫持行为的，所以需要特殊处理数组的变动，当然我们可以对于数组中每一个值进行循环然后通过索引同样使用",[17,116,23],{},"进行劫持，但是在",[17,119,19],{},"中尤大解释说是由于性能代价和获得的用户体验收益不成正比，所以并没有使用这种方式使下标访问实现响应式，具体可以参阅",[17,122,123],{},"github","中",[17,126,19],{},"源码的",[17,129,130],{},"#8562","。",[55,133,135],{"className":57,"code":134,"language":59,"meta":60,"style":60},"var obj = { __x: [1, 2, 3] };\nObject.defineProperty(obj, \"x\", {\n    set: function(x){ console.log(\"watch\"); this.__x = x; },\n    get: function(){ return this.__x; }\n});\nobj.x[0] = 11;\nconsole.log(obj.x); \u002F\u002F [11, 2, 3]\nobj.x = [1, 2, 3, 4, 5, 6]; \u002F\u002F watch\nconsole.log(obj.x); \u002F\u002F [1, 2, 3, 4, 5, 6]\nobj.x.push(7);\nconsole.log(obj.x); \u002F\u002F [1, 2, 3, 4, 5, 6, 7]\n",[17,136,137,142,146,150,154,158,163,168,174,180,186],{"__ignoreMap":60},[64,138,139],{"class":66,"line":67},[64,140,141],{},"var obj = { __x: [1, 2, 3] };\n",[64,143,144],{"class":66,"line":73},[64,145,76],{},[64,147,148],{"class":66,"line":79},[64,149,82],{},[64,151,152],{"class":66,"line":85},[64,153,88],{},[64,155,156],{"class":66,"line":91},[64,157,94],{},[64,159,160],{"class":66,"line":97},[64,161,162],{},"obj.x[0] = 11;\n",[64,164,165],{"class":66,"line":103},[64,166,167],{},"console.log(obj.x); \u002F\u002F [11, 2, 3]\n",[64,169,171],{"class":66,"line":170},8,[64,172,173],{},"obj.x = [1, 2, 3, 4, 5, 6]; \u002F\u002F watch\n",[64,175,177],{"class":66,"line":176},9,[64,178,179],{},"console.log(obj.x); \u002F\u002F [1, 2, 3, 4, 5, 6]\n",[64,181,183],{"class":66,"line":182},10,[64,184,185],{},"obj.x.push(7);\n",[64,187,189],{"class":66,"line":188},11,[64,190,191],{},"console.log(obj.x); \u002F\u002F [1, 2, 3, 4, 5, 6, 7]\n",[55,193,195],{"className":57,"code":194,"language":59,"meta":60,"style":60},"\u002F\u002F 通过下标对每一个值进行劫持\nvar obj = { __x: [1, 2, 3] };\nObject.defineProperty(obj, \"x\", {\n    set: function(x){ console.log(\"watch\"); this.__x = x; },\n    get: function(){ return this.__x; }\n});\nobj.x.forEach((v, i) => {\n    Object.defineProperty(obj.x, i,{\n        set:function(x) { console.log(\"watch\"); v = x; },\n        get: function(){ return v; }\n    })\n})\nobj.x[0] = 11; \u002F\u002F watch\nconsole.log(obj.x); \u002F\u002F [11, 2, 3]\n",[17,196,197,202,206,210,214,218,222,227,232,237,242,247,253,259],{"__ignoreMap":60},[64,198,199],{"class":66,"line":67},[64,200,201],{},"\u002F\u002F 通过下标对每一个值进行劫持\n",[64,203,204],{"class":66,"line":73},[64,205,141],{},[64,207,208],{"class":66,"line":79},[64,209,76],{},[64,211,212],{"class":66,"line":85},[64,213,82],{},[64,215,216],{"class":66,"line":91},[64,217,88],{},[64,219,220],{"class":66,"line":97},[64,221,94],{},[64,223,224],{"class":66,"line":103},[64,225,226],{},"obj.x.forEach((v, i) => {\n",[64,228,229],{"class":66,"line":170},[64,230,231],{},"    Object.defineProperty(obj.x, i,{\n",[64,233,234],{"class":66,"line":176},[64,235,236],{},"        set:function(x) { console.log(\"watch\"); v = x; },\n",[64,238,239],{"class":66,"line":182},[64,240,241],{},"        get: function(){ return v; }\n",[64,243,244],{"class":66,"line":188},[64,245,246],{},"    })\n",[64,248,250],{"class":66,"line":249},12,[64,251,252],{},"})\n",[64,254,256],{"class":66,"line":255},13,[64,257,258],{},"obj.x[0] = 11; \u002F\u002F watch\n",[64,260,262],{"class":66,"line":261},14,[64,263,167],{},[14,265,266,267,269,270,272,273,276],{},"在",[17,268,19],{},"中对于数据是经过特殊处理的，对于下标直接访问的修改同样是不能触发",[17,271,30],{},"，但是对于",[17,274,275],{},"push","等方法都进行了重写。",[55,278,282],{"className":279,"code":280,"language":281,"meta":60,"style":60},"language-html shiki shiki-themes github-light github-dark","\u003C!DOCTYPE html>\n\u003Chtml>\n\u003Chead>\n    \u003Ctitle>Vue中数组变动监听\u003C\u002Ftitle>\n\u003C\u002Fhead>\n\u003Cbody>\n    \u003Cdiv id=\"app\">\u003C\u002Fdiv>\n\u003C\u002Fbody>\n\u003Cscript src=\"https:\u002F\u002Fcdn.bootcss.com\u002Fvue\u002F2.4.2\u002Fvue.js\">\u003C\u002Fscript>\n\u003Cscript type=\"text\u002Fjavascript\">\n    var vm = new Vue({\n        el: '#app',\n        data: {\n            msg: [1, 2, 3]\n        },\n        template:`\n            \u003Cdiv>\n                \u003Cdiv v-for=\"item in msg\" :key=\"item\">{{item}}\u003C\u002Fdiv>\n                \u003Cbutton @click=\"subscript\">subscript\u003C\u002Fbutton>\n                \u003Cbutton @click=\"push\">push\u003C\u002Fbutton>\n            \u003C\u002Fdiv>\n        `,\n        methods:{\n            subscript: function(){\n                this.msg[0] = 11;\n                console.log(this.msg); \u002F\u002F [11, 2, 3, __ob__: Observer]\n            },\n            push: function(){\n                this.msg.push(4, 5, 6);\n                console.log(this.msg); \u002F\u002F [1, 2, 3, 4, 5, 6, __ob__: Observer]\n            }\n        }\n    })\n\u003C\u002Fscript>\n\u003C\u002Fhtml>\n","html",[17,283,284,301,310,319,334,343,352,376,384,405,421,441,452,457,480,486,495,501,507,513,519,525,533,539,554,577,599,605,617,645,661,667,673,678,687],{"__ignoreMap":60},[64,285,286,290,294,298],{"class":66,"line":67},[64,287,289],{"class":288},"sVt8B","\u003C!",[64,291,293],{"class":292},"s9eBZ","DOCTYPE",[64,295,297],{"class":296},"sScJk"," html",[64,299,300],{"class":288},">\n",[64,302,303,306,308],{"class":66,"line":73},[64,304,305],{"class":288},"\u003C",[64,307,281],{"class":292},[64,309,300],{"class":288},[64,311,312,314,317],{"class":66,"line":79},[64,313,305],{"class":288},[64,315,316],{"class":292},"head",[64,318,300],{"class":288},[64,320,321,324,327,330,332],{"class":66,"line":85},[64,322,323],{"class":288},"    \u003C",[64,325,326],{"class":292},"title",[64,328,329],{"class":288},">Vue中数组变动监听\u003C\u002F",[64,331,326],{"class":292},[64,333,300],{"class":288},[64,335,336,339,341],{"class":66,"line":91},[64,337,338],{"class":288},"\u003C\u002F",[64,340,316],{"class":292},[64,342,300],{"class":288},[64,344,345,347,350],{"class":66,"line":97},[64,346,305],{"class":288},[64,348,349],{"class":292},"body",[64,351,300],{"class":288},[64,353,354,356,359,362,365,369,372,374],{"class":66,"line":103},[64,355,323],{"class":288},[64,357,358],{"class":292},"div",[64,360,361],{"class":296}," id",[64,363,364],{"class":288},"=",[64,366,368],{"class":367},"sZZnC","\"app\"",[64,370,371],{"class":288},">\u003C\u002F",[64,373,358],{"class":292},[64,375,300],{"class":288},[64,377,378,380,382],{"class":66,"line":170},[64,379,338],{"class":288},[64,381,349],{"class":292},[64,383,300],{"class":288},[64,385,386,388,391,394,396,399,401,403],{"class":66,"line":176},[64,387,305],{"class":288},[64,389,390],{"class":292},"script",[64,392,393],{"class":296}," src",[64,395,364],{"class":288},[64,397,398],{"class":367},"\"https:\u002F\u002Fcdn.bootcss.com\u002Fvue\u002F2.4.2\u002Fvue.js\"",[64,400,371],{"class":288},[64,402,390],{"class":292},[64,404,300],{"class":288},[64,406,407,409,411,414,416,419],{"class":66,"line":182},[64,408,305],{"class":288},[64,410,390],{"class":292},[64,412,413],{"class":296}," type",[64,415,364],{"class":288},[64,417,418],{"class":367},"\"text\u002Fjavascript\"",[64,420,300],{"class":288},[64,422,423,427,430,432,435,438],{"class":66,"line":188},[64,424,426],{"class":425},"szBVR","    var",[64,428,429],{"class":288}," vm ",[64,431,364],{"class":425},[64,433,434],{"class":425}," new",[64,436,437],{"class":296}," Vue",[64,439,440],{"class":288},"({\n",[64,442,443,446,449],{"class":66,"line":249},[64,444,445],{"class":288},"        el: ",[64,447,448],{"class":367},"'#app'",[64,450,451],{"class":288},",\n",[64,453,454],{"class":66,"line":255},[64,455,456],{"class":288},"        data: {\n",[64,458,459,462,466,469,472,474,477],{"class":66,"line":261},[64,460,461],{"class":288},"            msg: [",[64,463,465],{"class":464},"sj4cs","1",[64,467,468],{"class":288},", ",[64,470,471],{"class":464},"2",[64,473,468],{"class":288},[64,475,476],{"class":464},"3",[64,478,479],{"class":288},"]\n",[64,481,483],{"class":66,"line":482},15,[64,484,485],{"class":288},"        },\n",[64,487,489,492],{"class":66,"line":488},16,[64,490,491],{"class":288},"        template:",[64,493,494],{"class":367},"`\n",[64,496,498],{"class":66,"line":497},17,[64,499,500],{"class":367},"            \u003Cdiv>\n",[64,502,504],{"class":66,"line":503},18,[64,505,506],{"class":367},"                \u003Cdiv v-for=\"item in msg\" :key=\"item\">{{item}}\u003C\u002Fdiv>\n",[64,508,510],{"class":66,"line":509},19,[64,511,512],{"class":367},"                \u003Cbutton @click=\"subscript\">subscript\u003C\u002Fbutton>\n",[64,514,516],{"class":66,"line":515},20,[64,517,518],{"class":367},"                \u003Cbutton @click=\"push\">push\u003C\u002Fbutton>\n",[64,520,522],{"class":66,"line":521},21,[64,523,524],{"class":367},"            \u003C\u002Fdiv>\n",[64,526,528,531],{"class":66,"line":527},22,[64,529,530],{"class":367},"        `",[64,532,451],{"class":288},[64,534,536],{"class":66,"line":535},23,[64,537,538],{"class":288},"        methods:{\n",[64,540,542,545,548,551],{"class":66,"line":541},24,[64,543,544],{"class":296},"            subscript",[64,546,547],{"class":288},": ",[64,549,550],{"class":425},"function",[64,552,553],{"class":288},"(){\n",[64,555,557,560,563,566,569,571,574],{"class":66,"line":556},25,[64,558,559],{"class":464},"                this",[64,561,562],{"class":288},".msg[",[64,564,565],{"class":464},"0",[64,567,568],{"class":288},"] ",[64,570,364],{"class":425},[64,572,573],{"class":464}," 11",[64,575,576],{"class":288},";\n",[64,578,580,583,586,589,592,595],{"class":66,"line":579},26,[64,581,582],{"class":288},"                console.",[64,584,585],{"class":296},"log",[64,587,588],{"class":288},"(",[64,590,591],{"class":464},"this",[64,593,594],{"class":288},".msg); ",[64,596,598],{"class":597},"sJ8bj","\u002F\u002F [11, 2, 3, __ob__: Observer]\n",[64,600,602],{"class":66,"line":601},27,[64,603,604],{"class":288},"            },\n",[64,606,608,611,613,615],{"class":66,"line":607},28,[64,609,610],{"class":296},"            push",[64,612,547],{"class":288},[64,614,550],{"class":425},[64,616,553],{"class":288},[64,618,620,622,625,627,629,632,634,637,639,642],{"class":66,"line":619},29,[64,621,559],{"class":464},[64,623,624],{"class":288},".msg.",[64,626,275],{"class":296},[64,628,588],{"class":288},[64,630,631],{"class":464},"4",[64,633,468],{"class":288},[64,635,636],{"class":464},"5",[64,638,468],{"class":288},[64,640,641],{"class":464},"6",[64,643,644],{"class":288},");\n",[64,646,648,650,652,654,656,658],{"class":66,"line":647},30,[64,649,582],{"class":288},[64,651,585],{"class":296},[64,653,588],{"class":288},[64,655,591],{"class":464},[64,657,594],{"class":288},[64,659,660],{"class":597},"\u002F\u002F [1, 2, 3, 4, 5, 6, __ob__: Observer]\n",[64,662,664],{"class":66,"line":663},31,[64,665,666],{"class":288},"            }\n",[64,668,670],{"class":66,"line":669},32,[64,671,672],{"class":288},"        }\n",[64,674,676],{"class":66,"line":675},33,[64,677,246],{"class":288},[64,679,681,683,685],{"class":66,"line":680},34,[64,682,338],{"class":288},[64,684,390],{"class":292},[64,686,300],{"class":288},[64,688,690,692,694],{"class":66,"line":689},35,[64,691,338],{"class":288},[64,693,281],{"class":292},[64,695,300],{"class":288},[14,697,266,698,700,701,704,705,708],{},[17,699,19],{},"中具体的重写方案是通过原型链来完成的，具体是通过",[17,702,703],{},"Object.create","方法创建一个新对象，使用传入的对象来作为新创建的对象的",[17,706,707],{},"__proto__","，之后对于特定的方法去拦截对数组的操作，从而实现对操作数组这个行为的监听。",[55,710,712],{"className":57,"code":711,"language":59,"meta":60,"style":60},"\u002F\u002F dev\u002Fsrc\u002Fcore\u002Fobserver\u002Farray.js\n\u002F*\n * not type checking this file because flow doesn't play well with\n * dynamically accessing methods on Array prototype\n *\u002F\n\nimport { def } from '..\u002Futil\u002Findex'\n\nconst arrayProto = Array.prototype\nexport const arrayMethods = Object.create(arrayProto)\n\nconst methodsToPatch = [\n  'push',\n  'pop',\n  'shift',\n  'unshift',\n  'splice',\n  'sort',\n  'reverse'\n]\n\n\u002F**\n * Intercept mutating methods and emit events\n *\u002F\nmethodsToPatch.forEach(function (method) {\n  \u002F\u002F cache original method\n  const original = arrayProto[method]\n  def(arrayMethods, method, function mutator (...args) {\n    const result = original.apply(this, args)\n    const ob = this.__ob__\n    let inserted\n    switch (method) {\n      case 'push':\n      case 'unshift':\n        inserted = args\n        break\n      case 'splice':\n        inserted = args.slice(2)\n        break\n    }\n    if (inserted) ob.observeArray(inserted)\n    \u002F\u002F notify change\n    ob.dep.notify()\n    return result\n  })\n})\n",[17,713,714,719,724,729,734,739,745,750,754,759,764,768,773,778,783,788,793,798,803,808,812,816,821,826,830,835,840,845,850,855,860,865,870,875,880,885,891,897,903,908,914,920,926,932,938,944],{"__ignoreMap":60},[64,715,716],{"class":66,"line":67},[64,717,718],{},"\u002F\u002F dev\u002Fsrc\u002Fcore\u002Fobserver\u002Farray.js\n",[64,720,721],{"class":66,"line":73},[64,722,723],{},"\u002F*\n",[64,725,726],{"class":66,"line":79},[64,727,728],{}," * not type checking this file because flow doesn't play well with\n",[64,730,731],{"class":66,"line":85},[64,732,733],{}," * dynamically accessing methods on Array prototype\n",[64,735,736],{"class":66,"line":91},[64,737,738],{}," *\u002F\n",[64,740,741],{"class":66,"line":97},[64,742,744],{"emptyLinePlaceholder":743},true,"\n",[64,746,747],{"class":66,"line":103},[64,748,749],{},"import { def } from '..\u002Futil\u002Findex'\n",[64,751,752],{"class":66,"line":170},[64,753,744],{"emptyLinePlaceholder":743},[64,755,756],{"class":66,"line":176},[64,757,758],{},"const arrayProto = Array.prototype\n",[64,760,761],{"class":66,"line":182},[64,762,763],{},"export const arrayMethods = Object.create(arrayProto)\n",[64,765,766],{"class":66,"line":188},[64,767,744],{"emptyLinePlaceholder":743},[64,769,770],{"class":66,"line":249},[64,771,772],{},"const methodsToPatch = [\n",[64,774,775],{"class":66,"line":255},[64,776,777],{},"  'push',\n",[64,779,780],{"class":66,"line":261},[64,781,782],{},"  'pop',\n",[64,784,785],{"class":66,"line":482},[64,786,787],{},"  'shift',\n",[64,789,790],{"class":66,"line":488},[64,791,792],{},"  'unshift',\n",[64,794,795],{"class":66,"line":497},[64,796,797],{},"  'splice',\n",[64,799,800],{"class":66,"line":503},[64,801,802],{},"  'sort',\n",[64,804,805],{"class":66,"line":509},[64,806,807],{},"  'reverse'\n",[64,809,810],{"class":66,"line":515},[64,811,479],{},[64,813,814],{"class":66,"line":521},[64,815,744],{"emptyLinePlaceholder":743},[64,817,818],{"class":66,"line":527},[64,819,820],{},"\u002F**\n",[64,822,823],{"class":66,"line":535},[64,824,825],{}," * Intercept mutating methods and emit events\n",[64,827,828],{"class":66,"line":541},[64,829,738],{},[64,831,832],{"class":66,"line":556},[64,833,834],{},"methodsToPatch.forEach(function (method) {\n",[64,836,837],{"class":66,"line":579},[64,838,839],{},"  \u002F\u002F cache original method\n",[64,841,842],{"class":66,"line":601},[64,843,844],{},"  const original = arrayProto[method]\n",[64,846,847],{"class":66,"line":607},[64,848,849],{},"  def(arrayMethods, method, function mutator (...args) {\n",[64,851,852],{"class":66,"line":619},[64,853,854],{},"    const result = original.apply(this, args)\n",[64,856,857],{"class":66,"line":647},[64,858,859],{},"    const ob = this.__ob__\n",[64,861,862],{"class":66,"line":663},[64,863,864],{},"    let inserted\n",[64,866,867],{"class":66,"line":669},[64,868,869],{},"    switch (method) {\n",[64,871,872],{"class":66,"line":675},[64,873,874],{},"      case 'push':\n",[64,876,877],{"class":66,"line":680},[64,878,879],{},"      case 'unshift':\n",[64,881,882],{"class":66,"line":689},[64,883,884],{},"        inserted = args\n",[64,886,888],{"class":66,"line":887},36,[64,889,890],{},"        break\n",[64,892,894],{"class":66,"line":893},37,[64,895,896],{},"      case 'splice':\n",[64,898,900],{"class":66,"line":899},38,[64,901,902],{},"        inserted = args.slice(2)\n",[64,904,906],{"class":66,"line":905},39,[64,907,890],{},[64,909,911],{"class":66,"line":910},40,[64,912,913],{},"    }\n",[64,915,917],{"class":66,"line":916},41,[64,918,919],{},"    if (inserted) ob.observeArray(inserted)\n",[64,921,923],{"class":66,"line":922},42,[64,924,925],{},"    \u002F\u002F notify change\n",[64,927,929],{"class":66,"line":928},43,[64,930,931],{},"    ob.dep.notify()\n",[64,933,935],{"class":66,"line":934},44,[64,936,937],{},"    return result\n",[64,939,941],{"class":66,"line":940},45,[64,942,943],{},"  })\n",[64,945,947],{"class":66,"line":946},46,[64,948,252],{},[36,950,951],{"id":951},"处理方法",[953,954,955],"h3",{"id":955},"重赋值",[14,957,958,960,961,964,965,968,969,972,973,976,977,979,980,983,984,986],{},[17,959,23],{},"方法无法劫持对于数组值下标方式访问的值的改变，这样的话就需要避免这种访问，可以采用修改后再赋值的方式，也可以采用数组中的一些方法去形成一个新数组，数组中不改变原数组并返回一个新数组的方法有",[17,962,963],{},"slice","、",[17,966,967],{},"concat","等方法以及",[17,970,971],{},"spread","操作符，当然也可以使用",[17,974,975],{},"map","方法生成新数组，此外在",[17,978,19],{},"中由于重写了",[17,981,982],{},"splice","方法，也可以使用",[17,985,982],{},"方法进行视图的更新。",[55,988,990],{"className":57,"code":989,"language":59,"meta":60,"style":60},"var obj = { __x: [1, 2, 3] };\nObject.defineProperty(obj, \"x\", {\n    set: function(x){ console.log(\"watch\"); this.__x = x; },\n    get: function(){ return this.__x; }\n});\n\nobj.x[0] = 11;\nobj.x = obj.x; \u002F\u002F watch\nconsole.log(obj.x); \u002F\u002F [11, 2, 3]\n\nobj.x[0] = 111;\nobj.x = [].concat(obj.x); \u002F\u002F watch\nconsole.log(obj.x); \u002F\u002F [111, 2, 3]\n\nobj.x[0] = 1111;\nobj.x = obj.x.slice(); \u002F\u002F watch\nconsole.log(obj.x); \u002F\u002F [1111, 2, 3]\n\nobj.x[0] = 11111;\nobj.x = obj.x.splice(0, obj.x.length); \u002F\u002F watch\nconsole.log(obj.x); \u002F\u002F [11111, 2, 3]\n",[17,991,992,996,1000,1004,1008,1012,1016,1020,1025,1029,1033,1038,1043,1048,1052,1057,1062,1067,1071,1076,1081],{"__ignoreMap":60},[64,993,994],{"class":66,"line":67},[64,995,141],{},[64,997,998],{"class":66,"line":73},[64,999,76],{},[64,1001,1002],{"class":66,"line":79},[64,1003,82],{},[64,1005,1006],{"class":66,"line":85},[64,1007,88],{},[64,1009,1010],{"class":66,"line":91},[64,1011,94],{},[64,1013,1014],{"class":66,"line":97},[64,1015,744],{"emptyLinePlaceholder":743},[64,1017,1018],{"class":66,"line":103},[64,1019,162],{},[64,1021,1022],{"class":66,"line":170},[64,1023,1024],{},"obj.x = obj.x; \u002F\u002F watch\n",[64,1026,1027],{"class":66,"line":176},[64,1028,167],{},[64,1030,1031],{"class":66,"line":182},[64,1032,744],{"emptyLinePlaceholder":743},[64,1034,1035],{"class":66,"line":188},[64,1036,1037],{},"obj.x[0] = 111;\n",[64,1039,1040],{"class":66,"line":249},[64,1041,1042],{},"obj.x = [].concat(obj.x); \u002F\u002F watch\n",[64,1044,1045],{"class":66,"line":255},[64,1046,1047],{},"console.log(obj.x); \u002F\u002F [111, 2, 3]\n",[64,1049,1050],{"class":66,"line":261},[64,1051,744],{"emptyLinePlaceholder":743},[64,1053,1054],{"class":66,"line":482},[64,1055,1056],{},"obj.x[0] = 1111;\n",[64,1058,1059],{"class":66,"line":488},[64,1060,1061],{},"obj.x = obj.x.slice(); \u002F\u002F watch\n",[64,1063,1064],{"class":66,"line":497},[64,1065,1066],{},"console.log(obj.x); \u002F\u002F [1111, 2, 3]\n",[64,1068,1069],{"class":66,"line":503},[64,1070,744],{"emptyLinePlaceholder":743},[64,1072,1073],{"class":66,"line":509},[64,1074,1075],{},"obj.x[0] = 11111;\n",[64,1077,1078],{"class":66,"line":515},[64,1079,1080],{},"obj.x = obj.x.splice(0, obj.x.length); \u002F\u002F watch\n",[64,1082,1083],{"class":66,"line":521},[64,1084,1085],{},"console.log(obj.x); \u002F\u002F [11111, 2, 3]\n",[953,1087,1089],{"id":1088},"proxy","Proxy",[14,1091,1092,1095,1096,1098,1099,1102,1103,1105,1106,1109,1110,1113,1114,1116],{},[17,1093,1094],{},"Vue3.0","使用",[17,1097,1089],{},"实现数据劫持，",[17,1100,1101],{},"Object.defineProperty","只能监听属性，而",[17,1104,1089],{},"能监听整个对象，通过调用",[17,1107,1108],{},"new Proxy()","，可以创建一个代理用来替代另一个对象被称为目标，这个代理对目标对象进行了虚拟，因此该代理与该目标对象表面上可以被当作同一个对象来对待。代理允许拦截在目标对象上的底层操作，而这原本是",[17,1111,1112],{},"Js","引擎的内部能力，拦截行为使用了一个能够响应特定操作的函数，即通过",[17,1115,1089],{},"去对一个对象进行代理之后，我们将得到一个和被代理对象几乎完全一样的对象，并且可以从底层实现对这个对象进行完全的监控。",[55,1118,1120],{"className":57,"code":1119,"language":59,"meta":60,"style":60},"var target = [1, 2, 3];\nvar proxy = new Proxy(target, {\n    set: function(target, key, value, receiver){ \n        console.log(\"watch\");\n        return Reflect.set(target, key, value, receiver);\n    },\n    get: function(target, key, receiver){ \n        return target[key];\n    }\n});\nproxy[0] = 11; \u002F\u002F watch\nconsole.log(target); \u002F\u002F [11, 2, 3]\n",[17,1121,1122,1127,1132,1137,1142,1147,1152,1157,1162,1166,1170,1175],{"__ignoreMap":60},[64,1123,1124],{"class":66,"line":67},[64,1125,1126],{},"var target = [1, 2, 3];\n",[64,1128,1129],{"class":66,"line":73},[64,1130,1131],{},"var proxy = new Proxy(target, {\n",[64,1133,1134],{"class":66,"line":79},[64,1135,1136],{},"    set: function(target, key, value, receiver){ \n",[64,1138,1139],{"class":66,"line":85},[64,1140,1141],{},"        console.log(\"watch\");\n",[64,1143,1144],{"class":66,"line":91},[64,1145,1146],{},"        return Reflect.set(target, key, value, receiver);\n",[64,1148,1149],{"class":66,"line":97},[64,1150,1151],{},"    },\n",[64,1153,1154],{"class":66,"line":103},[64,1155,1156],{},"    get: function(target, key, receiver){ \n",[64,1158,1159],{"class":66,"line":170},[64,1160,1161],{},"        return target[key];\n",[64,1163,1164],{"class":66,"line":176},[64,1165,913],{},[64,1167,1168],{"class":66,"line":182},[64,1169,94],{},[64,1171,1172],{"class":66,"line":188},[64,1173,1174],{},"proxy[0] = 11; \u002F\u002F watch\n",[64,1176,1177],{"class":66,"line":249},[64,1178,1179],{},"console.log(target); \u002F\u002F [11, 2, 3]\n",[36,1181,1182],{"id":1182},"每日一题",[55,1184,1189],{"className":1185,"code":1187,"language":1188},[1186],"language-text","https:\u002F\u002Fgithub.com\u002FWindrunnerMax\u002FEveryDay\n","text",[17,1190,1187],{"__ignoreMap":60},[36,1192,1193],{"id":1193},"参考",[55,1195,1198],{"className":1196,"code":1197,"language":1188},[1186],"https:\u002F\u002Fzhuanlan.zhihu.com\u002Fp\u002F50547367\nhttps:\u002F\u002Fgithub.com\u002Fvuejs\u002Fvue\u002Fissues\u002F8562\nhttps:\u002F\u002Fjuejin.im\u002Fpost\u002F6844903699425263629\nhttps:\u002F\u002Fjuejin.im\u002Fpost\u002F6844903597591773198\nhttps:\u002F\u002Fsegmentfault.com\u002Fa\u002F1190000015783546\nhttps:\u002F\u002Fcloud.tencent.com\u002Fdeveloper\u002Farticle\u002F1607061\nhttps:\u002F\u002Fwww.cnblogs.com\u002Ftugenhua0707\u002Fp\u002F11754291.html\nhttps:\u002F\u002Fdeveloper.mozilla.org\u002Fzh-CN\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FGlobal_Objects\u002FProxy\n",[17,1199,1197],{"__ignoreMap":60},[1201,1202,1203],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}",{"title":60,"searchDepth":73,"depth":73,"links":1205},[1206,1207,1211,1212],{"id":38,"depth":73,"text":38},{"id":951,"depth":73,"text":951,"children":1208},[1209,1210],{"id":955,"depth":79,"text":955},{"id":1088,"depth":79,"text":1089},{"id":1182,"depth":73,"text":1182},{"id":1193,"depth":73,"text":1193},"Vue的通过数据劫持的方式实现数据的双向绑定，即使用Object.defineProperty()来实现对属性的劫持，但是Object.defineProperty()中的setter是无法直接实现数组中值的改变的劫持行为的，想要实现对于数组下标直接访问的劫持需要使用索引对每一个值进行劫持，但是在Vue中考虑性能问题并未采用这种方式，所以需要特殊处理数组的变动。","md",{},"\u002Fvue\u002Fvue中数组变动监听",{"title":5,"description":1213},"Vue\u002FVue中数组变动监听","MKD7uZEbJ_4dkLc7jgL-OC3CzOsfHrleXXWPnLQXdcU",1791042470304]