Vá mã nguồn

Đôi khi, chúng ta cần tùy chỉnh cách hoạt động của giao diện người dùng. Nhiều nhu cầu chung được đáp ứng bởi một số API được hỗ trợ. Ví dụ: tất cả các sổ đăng ký đều là điểm mở rộng tốt: sổ đăng ký trường cho phép thêm/xóa các thành phần trường chuyên biệt hoặc sổ đăng ký thành phần chính cho phép thêm các thành phần cần được hiển thị mọi lúc.

Tuy nhiên, có những tình huống mà nó không đủ. Trong những trường hợp đó, chúng ta có thể cần sửa đổi một đối tượng hoặc một lớp tại chỗ. Để đạt được điều đó, SoOn cung cấp chức năng tiện ích patch. Việc ghi đè/cập nhật hành vi của một số thành phần/đoạn mã khác mà người ta không kiểm soát hầu hết đều hữu ích.

Sự miêu tả

Chức năng vá lỗi nằm ở @web/core/utils/patch:

patch(objToPatch, extension)
Đối số
  • objToPatch (object()) -- đối tượng cần được vá

  • extension (object()) -- một đối tượng ánh xạ từng khóa tới một phần mở rộng

Trả về

một chức năng để loại bỏ các bản vá

Hàm patch sửa đổi tại chỗ đối tượng (hoặc lớp) objToPatch và áp dụng tất cả khóa/giá trị được mô tả trong đối tượng extension. Một chức năng hủy bản vá được trả về, vì vậy nó có thể được sử dụng để xóa bản vá sau này nếu cần.

Hầu hết các thao tác vá lỗi đều cung cấp quyền truy cập vào giá trị gốc bằng cách sử dụng từ khóa super gốc (xem bên dưới trong các ví dụ).

Vá một đối tượng đơn giản

Đây là một ví dụ đơn giản về cách vá một đối tượng:

import { patch } from "@web/core/utils/patch";

const object = {
  field: "a field",
  fn() {
    // do something
  },
};

patch(object, {
  fn() {
    // do things
  },
});

Khi vá các hàm, chúng ta thường muốn có thể truy cập được hàm parent. Để làm như vậy, chúng ta chỉ cần sử dụng từ khóa super gốc:

patch(object, {
  fn() {
    super.fn(...arguments);
    // do other things
  },
});

Cảnh báo

super chỉ có thể được sử dụng trong một phương thức chứ không phải trong một hàm. Điều này có nghĩa là các cấu trúc sau không hợp lệ đối với javascript.

const obj = {
  a: function () {
    // Throws: "Uncaught SyntaxError: 'super' keyword unexpected here"
    super.a();
  },
  b: () => {
    // Throws: "Uncaught SyntaxError: 'super' keyword unexpected here"
    super.b();
  },
};

Getters và setters cũng được hỗ trợ:

patch(object, {
  get number() {
    return super.number / 2;
  },
  set number(value) {
    super.number = value;
  },
});

Vá một lớp javascript

Hàm patch được thiết kế để hoạt động với mọi thứ: đối tượng hoặc lớp ES6.

Tuy nhiên, vì các lớp javascript hoạt động với tính kế thừa nguyên mẫu, nên khi một người muốn vá một phương thức tiêu chuẩn từ một lớp, thì chúng ta thực sự cần phải vá nguyên mẫu:

class MyClass {
  static myStaticFn() {...}
  myPrototypeFn() {...}
}

// this will patch static properties!!!
patch(MyClass, {
  myStaticFn() {...},
});

// this is probably the usual case: patching a class method
patch(MyClass.prototype, {
  myPrototypeFn() {...},
});

Ngoài ra, Javascript xử lý hàm tạo theo cách riêng đặc biệt khiến không thể vá được. Cách giải quyết duy nhất là gọi một phương thức trong hàm tạo ban đầu và thay vào đó vá phương thức đó:

class MyClass {
  constructor() {
    this.setup();
  }
  setup() {
    this.number = 1;
  }
}

patch(MyClass.prototype, {
  setup() {
    super.setup(...arguments);
    this.doubleNumber = this.number * 2;
  },
});

Cảnh báo

Không thể vá trực tiếp hàm tạo của một lớp!

Vá một thành phần

Các thành phần được xác định bởi các lớp javascript nên tất cả thông tin ở trên vẫn được giữ nguyên. Vì những lý do này, các thành phần Owl nên sử dụng phương thức setup để chúng cũng có thể được vá dễ dàng (xem phần về các phương pháp hay nhất).

patch(MyComponent.prototype, {
  setup() {
    useMyHook();
  },
});

Xóa một bản vá

Hàm patch trả về bản sao của nó. Điều này chủ yếu hữu ích cho mục đích thử nghiệm, khi chúng tôi vá một cái gì đó khi bắt đầu thử nghiệm và hủy vá nó ở cuối.

const unpatch = patch(object, { ... });
// test stuff here
unpatch();

Áp dụng cùng một bản vá cho nhiều đối tượng

Có thể xảy ra trường hợp người ta muốn áp dụng cùng một bản vá cho nhiều đối tượng nhưng do cách hoạt động của từ khóa super, tiện ích mở rộng chỉ có thể được sử dụng để vá một lần và không thể sao chép/nhân bản (kiểm tra tài liệu của từ khóa). Một hàm trả về đối tượng được sử dụng để vá có thể được sử dụng để làm cho nó trở nên duy nhất.

const obj1 = {
  method() {
    doSomething();
  },
};

const obj2 = {
  method() {
    doThings();
  },
};

function createExtensionObj() {
  return {
    method() {
      super.method();
      doCommonThings();
    },
  };
}

patch(obj1, createExtensionObj());
patch(obj2, createExtensionObj());

Cảnh báo

Nếu một tiện ích mở rộng dựa trên một tiện ích mở rộng khác thì hai tiện ích mở rộng đó phải được áp dụng riêng biệt. Không sao chép/sao chép một phần mở rộng.

const object = {
  method1() {
    doSomething();
  },
  method2() {
    doAnotherThing();
  },
};

const ext1 = {
  method1() {
    super.method1();
    doThings();
  },
};

const invalid_ext2 = {
  ...ext1, // this will not work: super will not refer to the correct object in methods coming from ext1
  method2() {
    super.method2();
    doOtherThings();
  },
};

patch(object, invalid_ext2);
object.method1(); // throws: Uncaught TypeError: (intermediate value).method1 is not a function

const valid_ext2 = {
  method2() {
    super.method2();
    doOtherThings();
  },
};

patch(object, ext1); // first patch base extension
patch(object, valid_ext2); // then the new one
object.method1(); // works as expected