Điểm dừng về thay đổi tài sản


147

Firebug for Firefox có một tính năng hay, được gọi là "Phá vỡ thay đổi thuộc tính", nơi tôi có thể đánh dấu bất kỳ thuộc tính nào của bất kỳ đối tượng nào và nó sẽ dừng thực thi JavaScript ngay trước khi thay đổi.

Tôi đang cố gắng đạt được điều tương tự trong Google Chrome và tôi không thể tìm thấy chức năng trong trình gỡ lỗi Chrome. Làm cách nào để làm điều này trong Google Chrome?


1
Nếu bạn muốn làm điều này với các phần tử HTML, hãy xem stackoverflow.com/a/32686203/308851
chx

Câu trả lời:


106

Nếu bạn không bận tâm đến việc gây rối với nguồn, bạn có thể xác định lại tài sản với một người truy cập.

// 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
Có một phích cắm trong đó sẽ làm điều đó cho tôi?
Asen Zahray

3
@ArsenZahray, dunno. Tuy nhiên, bạn có thể tạo một chức năng tiện dụng từ nó và sử dụng như thế nào console.watch(obj, 'someProp').
katspaugh

5
Điều này không hoạt động cho các thuộc tính tích hợp như vì window.locationlý do bảo mật.
qJake

1
Để gỡ lỗi setters cho các phần tử DOM, mẫu này cần được sửa đổi một chút. Xem mnaoumov.wordpress.com/2015/11/29/ Khăn để biết thêm chi tiết
mnaoumov

@katspaugh tôi có thể hỏi tại sao bạn cần điều này không obj._someProp = obj.someProp;, có vẻ như không liên quan đến những gì bạn đang cố gắng lưu trữ (có lẽ vì tôi đang mất tích vào lúc nào đó)
Victor

109

Chỉnh sửa 2016.03: Object.observekhông dùng nữa và bị xóa trong Chrome 50

Chỉnh sửa 2014.05: Object.observeđã được thêm vào Chrome 36

Các tàu Chrome 36 có Object.observetriển khai riêng có thể được tận dụng tại đây:

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

Nếu bạn chỉ muốn tạm thời, bạn nên lưu trữ gọi lại trong một biến và gọi Object.unobservekhi hoàn tất:

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

Lưu ý rằng khi sử dụng Object.observe, bạn sẽ không được thông báo khi bài tập không thay đổi bất cứ điều gì, ví dụ nếu bạn đã viết myObj.a = 1.

Để xem ngăn xếp cuộc gọi, bạn cần bật tùy chọn "async call stack" trong Dev Tools:

ngăn xếp cuộc gọi chrome async


Câu trả lời gốc (2012/07):

Một console.watchbản phác thảo theo đề xuất của @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;
       }
   });
}

Cầu nguyện:

console.watch(obj, "someProp");

Khả năng tương thích:

  • Trong Chrome 20, bạn có thể dán trực tiếp vào Dev Tools khi chạy!
  • Để hoàn thiện: trong Fireorms 1.10 (Firefox 14), bạn phải đưa nó vào trang web của mình (ví dụ: qua Fiddler nếu bạn không thể chỉnh sửa nguồn theo cách thủ công); thật đáng buồn, các chức năng được xác định từ Fireorms dường như không bị debuggerhỏng (hoặc đó là vấn đề về cấu hình? vui lòng sửa lại cho tôi sau đó), nhưng vẫn console.loghoạt động.

Biên tập:

Lưu ý rằng trong Firefox, console.watchđã tồn tại, do không chuẩn của Firefox Object.watch. Do đó trong Firefox, bạn có thể theo dõi các thay đổi nguyên bản:

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

Tuy nhiên, điều này sẽ sớm bị xóa (cuối năm 2017) .


1
Nhân tiện, dường như không thể đánh vào trình gỡ lỗi trong mã tùy chỉnh là một hồi quy giữa Fireorms 1.8 và 1.9: vấn đề 5757 -> trùng lặp vấn đề 5221
jakub.g

1
@ColeReed chúng ta phải lưu trữ giá trị ở đâu đó để lấy nó trong getter; nó không thể được lưu trữ trong oObj[sProp], bởi vì getter sẽ nhập một đệ quy vô hạn. Hãy dùng thử trong Chrome, bạn sẽ nhận được RangeError: Maximum call stack size exceeded.
jakub.g

1
I "d như để thêm video này, như các asynchộp kiểm là rất vàng với cách tiếp cận này: html5rocks.com/en/tutorials/developertools/async-call-stack
CNP

1
@PhiLho Có thể thấy ngăn xếp, với asynchộp kiểm như @cnp đã viết, xem cập nhật của tôi
jakub.g

1
Nên cập nhật câu trả lời này: Object.observekhông được dùng nữa và sẽ sớm bị xóa: xem: chromestatus.com/features/6147094632988672
Amir Gonnen 15/03/2016

79

Có một thư viện cho việc này: BreakOn ()

Nếu bạn thêm nó vào các công cụ phát triển của Chrome dưới dạng đoạn trích (nguồn -> đoạn trích -> nhấp chuột phải -> mới -> dán mục này ) , bạn có thể sử dụng nó bất cứ lúc nào.


Để sử dụng nó, hãy mở các công cụ dev và chạy đoạn trích. Sau đó để ngắt khi myObject.myPropertyđược thay đổi, hãy gọi nó từ dev-console:

breakOn(myObject, 'myProperty');

Bạn cũng có thể thêm thư viện vào bản dựng gỡ lỗi của dự án để bạn không cần gọi breakOnlại mỗi khi bạn làm mới trang.


5

Điều này cũng có thể được thực hiện bằng cách sử dụng đối tượng Proxy mới có mục đích chính xác là: chặn việc đọc và ghi vào đối tượng được bao bọc bởi Proxy. Bạn chỉ cần bọc đối tượng bạn muốn quan sát vào Proxy và sử dụng đối tượng được bọc mới thay vì đối tượng ban đầu.

Thí dụ:

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);

Bây giờ, sử dụng WraObject nơi bạn sẽ cung cấp gốcObject thay vào đó và kiểm tra ngăn xếp cuộc gọi khi nghỉ.


Proxy setphải trả lại trueđể nó không bị lỗi đối với các trường hợp khác được theo dõi.
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

Quyết định viết phiên bản riêng của giải pháp này, lưu nó vào một đoạn trong DevTools của Chrome và gói nó trong IIFE hỗ trợ cả Nút và Trình duyệt. Đồng thời thay đổi người quan sát sử dụng biến phạm vi thay vì thuộc tính trên đối tượng, sao cho không có khả năng xảy ra xung đột tên và bất kỳ mã nào liệt kê các khóa sẽ không "nhìn thấy" khóa riêng "mới được tạo:

(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 có tính năng này tích hợp trong các phiên bản mới nhất https://developers.google.com/web/updates/2015/05/view-and-change-your-dom-breakpoint .

Vì vậy, không cần thêm các thư viện và giải pháp tùy chỉnh, chỉ cần nhấp chuột phải vào phần tử DOM trong trình kiểm tra và chọn 'Break on' -> 'sửa đổi thuộc tính' và đó là nó.


10
Anh ta yêu cầu thay đổi thuộc tính (đối tượng js), không thay đổi giá trị thuộc tính DOM
Z. Khullah

1
@Ivica Đây là một kỹ thuật tốt, nhưng đây là nơi sai lầm để đặt nó. Nó sẽ tốt như một bình luận, nhưng không phải là một câu trả lời.
bnieland
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.