Tôi biết tôi đến muộn bữa tiệc nhưng đây là một phương pháp ngắn hơn phù hợp với những nỗ lực ban đầu của bạn.
a.replace('f', String.call.bind(a.toUpperCase));
Vậy bạn đã sai ở đâu và voodoo mới này là gì?
Vấn đề 1
Như đã nêu trước đây, bạn đang cố gắng chuyển các kết quả của một phương thức được gọi làm tham số thứ hai của String.prototype.replace () , thay vào đó, bạn nên chuyển một tham chiếu đến một hàm
Giải pháp 1
Điều đó đủ dễ dàng để giải quyết. Đơn giản chỉ cần loại bỏ các tham số và dấu ngoặc đơn sẽ cung cấp cho chúng ta một tham chiếu hơn là thực thi hàm.
a.replace('f', String.prototype.toUpperCase.apply)
Vấn đề 2
Nếu bạn cố gắng chạy mã ngay bây giờ, bạn sẽ gặp lỗi cho biết rằng undefined không phải là một hàm và do đó không thể được gọi. Điều này là do String.prototype.toUpperCase.apply thực sự là một tham chiếu đến Function.prototype.apply () thông qua kế thừa nguyên mẫu của JavaScript. Vì vậy, những gì chúng tôi đang thực sự làm trông giống như thế này
a.replace('f', Function.prototype.apply)
Đó rõ ràng không phải là những gì chúng tôi đã dự định. Làm thế nào nó biết để chạy Function.prototype.apply () trên String.prototype.toUpperCase () ?
Giải pháp 2
Sử dụng Function.prototype.bind (), chúng ta có thể tạo một bản sao của Function.prototype.call với ngữ cảnh của nó được đặt cụ thể thành String.prototype.toUpperCase. Bây giờ chúng tôi có những thứ sau
a.replace('f', Function.prototype.apply.bind(String.prototype.toUpperCase))
Vấn đề 3
Vấn đề cuối cùng là String.prototype.replace () sẽ truyền một số đối số cho hàm thay thế của nó. Tuy nhiên, Function.prototype.apply () mong muốn tham số thứ hai là một mảng nhưng thay vào đó nhận một chuỗi hoặc số (tùy thuộc vào việc bạn có sử dụng nhóm nắm bắt hay không). Điều này sẽ gây ra lỗi danh sách đối số không hợp lệ.
Giải pháp 3
May mắn thay, chúng ta chỉ có thể thay thế trong Function.prototype.call () (chấp nhận bất kỳ số lượng đối số nào, không có đối số nào có giới hạn kiểu) cho Function.prototype.apply () . Bây giờ chúng tôi đã đến mã làm việc!
a.replace(/f/, Function.prototype.call.bind(String.prototype.toUpperCase))
Bỏ từng byte!
Không ai muốn nhập nguyên mẫu nhiều lần. Thay vào đó, chúng ta sẽ tận dụng thực tế là chúng ta có các đối tượng tham chiếu đến các phương thức giống nhau thông qua kế thừa. Phương thức khởi tạo Chuỗi, là một hàm, kế thừa từ nguyên mẫu của Hàm. Điều này có nghĩa là chúng ta có thể thay thế trong String.call cho Function.prototype.call (thực ra chúng ta có thể sử dụng Date.call để tiết kiệm nhiều byte hơn nhưng ít ngữ nghĩa hơn).
Chúng tôi cũng có thể tận dụng biến 'a' của mình vì nguyên mẫu của nó bao gồm một tham chiếu đến String.prototype.toUpperCase, chúng tôi có thể hoán đổi biến đó với a.toUpperCase. Đó là sự kết hợp của 3 giải pháp ở trên và các biện pháp tiết kiệm byte này là cách chúng tôi lấy mã ở đầu bài đăng này.