จุดพักบนการเปลี่ยนแปลงคุณสมบัติ


147

Firebug สำหรับ Firefox มีคุณสมบัติที่ดีเรียกว่า "การเปลี่ยนแปลงคุณสมบัติ" ซึ่งฉันสามารถทำเครื่องหมายคุณสมบัติของวัตถุใด ๆ และจะหยุดการทำงานของ JavaScript ก่อนการเปลี่ยนแปลง

ฉันพยายามทำสิ่งเดียวกันให้สำเร็จใน Google Chrome และฉันไม่พบฟังก์ชันในการดีบักเกอร์ของ Chrome ฉันจะทำสิ่งนี้ใน Google Chrome ได้อย่างไร


1
หากคุณต้องการทำสิ่งนี้กับองค์ประกอบ HTML ดูstackoverflow.com/a/32686203/308851
chx

คำตอบ:


106

หากคุณไม่ได้ยุ่งกับแหล่งข้อมูลคุณสามารถกำหนดคุณสมบัติใหม่ด้วย accessor

// original object
var obj = {
    someProp: 10
};

// save in another property
obj._someProp = obj.someProp;

// overwrite with accessor
Object.defineProperty(obj, 'someProp', {
    get: function () {
        return obj._someProp;
    },

    set: function (value) {
        debugger; // sets breakpoint
        obj._someProp = value;
    }
});

2
มีปลั๊กที่จะทำสำหรับฉัน
Arsen Zahray

3
@ArsenZahray, dunno อย่างไรก็ตามคุณสามารถสร้างฟังก์ชั่นที่ใช้งานง่ายและใช้งานconsole.watch(obj, 'someProp')ได้
katspaugh

5
สิ่งนี้ไม่ทำงานสำหรับคุณสมบัติที่มีอยู่ภายในเช่นwindow.locationเหตุผลด้านความปลอดภัย
qJake

1
ในการดีบัก setters สำหรับองค์ประกอบ DOM รูปแบบนี้ควรมีการปรับเปลี่ยนเล็กน้อย ดูmnaoumov.wordpress.com/2015/11/29/…สำหรับรายละเอียดเพิ่มเติม
mnaoumov

@katspaugh ฉันจะถามว่าทำไมคุณต้องนี้obj._someProp = obj.someProp;ดูเหมือนว่าไม่เกี่ยวข้องเกี่ยวกับสิ่งที่คุณกำลังพยายามที่จะ archieve (อาจจะเป็นเพราะฉันหายไป somethign)
วิคเตอร์

109

แก้ไข 2016.03: Object.observeเลิกใช้แล้วและถูกลบใน Chrome 50

แก้ไข 2014.05: Object.observeถูกเพิ่มใน Chrome 36

Chrome 36 มาพร้อมกับObject.observeการติดตั้งในตัวซึ่งสามารถใช้งานได้ที่นี่

myObj = {a: 1, b: 2};
Object.observe(myObj, function (changes){
    console.log("Changes:");
    console.log(changes);
    debugger;
})
myObj.a = 42;

หากคุณต้องการเพียงชั่วคราวคุณควรจัดเก็บการโทรกลับในตัวแปรและโทรObject.unobserveเมื่อเสร็จแล้ว:

myObj = {a: 1, b: 2};
func = function() {debugger;}
Object.observe(myObj, func);
myObj.a = 42;
Object.unobserve(myObj, func);
myObj.a = 84;

หมายเหตุว่าเมื่อใช้คุณจะไม่ได้รับการแจ้งเตือนเมื่อได้รับมอบหมายไม่ได้เปลี่ยนแปลงอะไรเช่นถ้าคุณเขียนObject.observemyObj.a = 1

หากต้องการดู call stack คุณต้องเปิดใช้งานตัวเลือก "async call stack" ในเครื่องมือ Dev:

chrome async call stack


คำตอบเดิม (2012.07):

console.watchร่างตามที่แนะนำโดย @katspaugh:

var console = console || {}; // just in case
console.watch = function(oObj, sProp) {
   var sPrivateProp = "$_"+sProp+"_$"; // to minimize the name clash risk
   oObj[sPrivateProp] = oObj[sProp];

   // overwrite with accessor
   Object.defineProperty(oObj, sProp, {
       get: function () {
           return oObj[sPrivateProp];
       },

       set: function (value) {
           //console.log("setting " + sProp + " to " + value); 
           debugger; // sets breakpoint
           oObj[sPrivateProp] = value;
       }
   });
}

ภาวนา:

console.watch(obj, "someProp");

เข้ากันได้:

  • ใน Chrome 20 คุณสามารถวางโดยตรงใน Dev Tools ตอนรันไทม์!
  • เพื่อความสมบูรณ์: ใน Firebug 1.10 (Firefox 14) คุณต้องแทรกไว้ในเว็บไซต์ของคุณ (เช่นผ่าน Fiddler หากคุณไม่สามารถแก้ไขต้นฉบับด้วยตนเอง); น่าเศร้าที่ฟังก์ชั่นที่กำหนดจาก Firebug ดูเหมือนจะไม่แตกหักdebugger(หรือเป็นเรื่องของการกำหนดค่าหรือไม่โปรดแก้ไขให้ฉันด้วย) แต่ใช้console.logงานได้

แก้ไข:

โปรดทราบว่าใน Firefox console.watchอยู่แล้วเนื่องจากของ Firefox Object.watchที่ไม่ได้มาตรฐาน ดังนั้นใน Firefox คุณสามารถดูการเปลี่ยนแปลงได้ที่:

>>> var obj = { foo: 42 }
>>> obj.watch('foo', function() { console.log('changed') })
>>> obj.foo = 69
changed
69

แต่นี้จะเป็นเร็ว ๆ นี้ (ปลาย 2017) ลบออก


1
โดยวิธีการดูเหมือนว่าไม่สามารถที่จะตีดีบักเกอร์ในรหัสที่กำหนดเองคือการถดถอยระหว่าง Firebug 1.8 และ 1.9: ปัญหา 5757 -> ซ้ำของปัญหา 5221
jakub.g

1
@ColeReed เราต้องเก็บค่าไว้ที่ใดที่หนึ่งเพื่อรับค่าใน getter; มันไม่สามารถเก็บไว้ในoObj[sProp]ได้เพราะทะเยอทะยานจะเข้าสู่การสอบถามซ้ำไม่สิ้นสุด ลองมันใน Chrome RangeError: Maximum call stack size exceededคุณจะได้รับ
jakub.g

1
ฉันต้องการเพิ่มสิ่งนี้เนื่องจากasyncช่องทำเครื่องหมายเป็นสีทองด้วยวิธีการนี้: html5rocks.com/en/tutorials/developertools/async-call-stack
cnp

1
@PhiLho เป็นไปได้ที่จะเห็นสแต็คโดยมีasyncช่องทำเครื่องหมายตามที่ @cnp เขียนดูการอัปเดตของฉัน
jakub.g

1
ควรอัปเดตคำตอบนี้: Object.observeเลิกใช้แล้วและอีกไม่นานจะถูกลบออก: ดู: chromestatus.com/features/6147094632988672
Amir Gonnen

79

มีห้องสมุดสำหรับสิ่งนี้คือ: BreakOn ()

หากคุณเพิ่มลงในเครื่องมือพัฒนา Chrome เป็นตัวอย่าง(แหล่งที่มา -> ตัวอย่าง -> คลิกขวา -> ใหม่ -> วางสิ่งนี้ )คุณสามารถใช้มันได้ทุกเมื่อ


หากต้องการใช้งานให้เปิดเครื่องมือ dev และเรียกใช้ข้อมูลโค้ด จากนั้นให้หยุดเมื่อmyObject.myPropertyมีการเปลี่ยนแปลงให้เรียกสิ่งนี้จาก dev-console:

breakOn(myObject, 'myProperty');

นอกจากนี้คุณยังสามารถเพิ่มห้องสมุดไปยังการแก้ไขข้อบกพร่องของโครงการของคุณเพื่อให้คุณไม่จำเป็นต้องโทรbreakOnอีกครั้งทุกครั้งที่รีเฟรชหน้า


5

สิ่งนี้สามารถทำได้โดยการใช้วัตถุพร็อกซีใหม่ซึ่งมีวัตถุประสงค์ตรงที่: การสกัดกั้นการอ่านและการเขียนไปยังวัตถุที่ถูกห่อโดยพร็อกซี คุณเพียงแค่ห่อวัตถุที่คุณต้องการจะสังเกตเข้าไปในหนังสือมอบฉันทะและใช้วัตถุที่ถูกห่อใหม่แทนที่จะเป็นวัตถุดั้งเดิม

ตัวอย่าง:

const originalObject = {property: 'XXX', propertyToWatch: 'YYY'};
const watchedProp = 'propertyToWatch';
const handler = {
  set(target, key, value) {
    if (key === watchedProp) {
      debugger;
    }
    target[key] = value;
  }
};
const wrappedObject = new Proxy(originalObject, handler);

ตอนนี้ใช้ wraObject ที่คุณจะจัดหา originalObject แทนและตรวจสอบ call stack เมื่อพัก


พร็อกซีsetต้องส่งคืนtrueเพื่อไม่ให้ล้มเหลวนอกเหนือจากกรณีที่ถูกติดตาม
keaukraine

4
function debugProperty(obj, propertyName) {
  // save in another property
  obj['_' + propertyName] = obj[propertyName];

  // overwrite with accessor
  Object.defineProperty(obj, propertyName, {
    get: function() {
      return obj['_' + propertyName];
    },

    set: function(value) {
      debugger; // sets breakpoint
      obj['_' + propertyName] = value;
    }
  });
}

1

ตัดสินใจเขียนโซลูชันนี้ในเวอร์ชันของฉันเองบันทึกไว้ในตัวอย่างใน DevTools ของ Chrome และห่อไว้ใน IIFE ที่ควรสนับสนุนทั้งโหนดและเบราว์เซอร์ เปลี่ยนผู้สังเกตการณ์ให้ใช้ตัวแปรขอบเขตแทนคุณสมบัติบนวัตถุเช่นนั้นจะไม่มีความเป็นไปได้ของการปะทะกันของชื่อและรหัสใด ๆ ที่ระบุคีย์จะไม่ "เห็น" คีย์ส่วนตัว "ใหม่ที่สร้างขึ้น:

(function (global) {
  global.observeObject = (obj, prop) => {
    let value

    Object.defineProperty(obj, prop, {
      get: function () {
        return value
      },

      set: function (newValue) {
        debugger
        value = newValue
      },
    })
  }
})(typeof process !== 'undefined' ? process : window)

-2

Chrome มีคุณลักษณะนี้ในตัวในรุ่นล่าสุดhttps://developers.google.com/web/updates/2015/05/view-and-change-your-dom-breakpoints

ดังนั้นไม่จำเป็นต้องใช้ไลบรารีและโซลูชันที่กำหนดเองอีกต่อไปเพียงแค่คลิกขวาที่องค์ประกอบ DOM ในตัวตรวจสอบและเลือก 'หยุดพัก' -> 'ปรับเปลี่ยนแอตทริบิวต์' และนั่นคือสิ่งที่ต้องการ


10
เขาขอการเปลี่ยนแปลงคุณสมบัติ (วัตถุ js) ไม่ใช่การเปลี่ยนค่าแอตทริบิวต์ DOM
Z. Khullah

1
@Ivica นี่เป็นเทคนิคที่ดี แต่นี่เป็นสถานที่ที่ไม่ถูกต้อง มันจะไม่เป็นความคิดเห็น แต่ก็ไม่ใช่คำตอบ
bnieland
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.