Thêm mã vào hàm javascript theo chương trình


114

Tôi đang cố gắng tùy chỉnh thư viện JS hiện có mà không sửa đổi mã JS gốc. Mã này tải trong một vài tệp JS bên ngoài mà tôi có quyền truy cập và những gì tôi muốn làm là thay đổi một trong các chức năng có trong tệp gốc mà không cần sao chép và dán toàn bộ vào tệp JS thứ hai.
Vì vậy, ví dụ: giới hạn tắt JS có thể có một chức năng như sau:

var someFunction = function(){
    alert("done");
}

Tôi muốn bằng cách nào đó có thể nối hoặc thêm một số mã JS vào hàm đó. Lý do chủ yếu là trong JS không thể chạm vào ban đầu, chức năng này khá lớn và nếu JS đó được cập nhật, chức năng tôi ghi đè lên nó sẽ lỗi thời.

Tôi không hoàn toàn chắc chắn điều này có thể xảy ra, nhưng tôi nghĩ rằng tôi sẽ kiểm tra.


3
câu trả lời đầu tiên của điều này sẽ giúp bạn
DarkAjax

Bạn có muốn một cái gì đó giống như một chức năng gọi lại?
sinemetu1

Câu trả lời:


219

Nếu someFunctioncó sẵn trên toàn cầu, thì bạn có thể lưu vào bộ nhớ cache của hàm, tạo hàm của riêng bạn và gọi hàm của bạn.

Vì vậy, nếu đây là bản gốc ...

someFunction = function() {
    alert("done");
}

Bạn sẽ làm điều này ...

someFunction = (function() {
    var cached_function = someFunction;

    return function() {
        // your code

        var result = cached_function.apply(this, arguments); // use .apply() to call it

        // more of your code

        return result;
    };
})();

Đây là trò chơi


Lưu ý rằng tôi sử dụng .applyđể gọi hàm được lưu trong bộ nhớ cache. Điều này cho phép tôi giữ lại giá trị mong đợi thisvà chuyển bất kỳ đối số nào được chuyển vào dưới dạng đối số riêng lẻ bất kể có bao nhiêu đối số.


10
Câu trả lời này thực sự nên là câu hàng đầu - nó bảo toàn chức năng của hàm được đề cập ... +1 từ tôi.
Reid

17
+1 để sử dụng apply: đây là câu trả lời duy nhất thực sự giải quyết được vấn đề.
một

2
@minitech: Gì ... Bạn không quen với funcitontừ khóa của JavaScript ? ;) Cảm ơn đã sửa

1
@gdoron: Tôi vừa thêm một nhận xét. Trừ khi tôi thực sự bối rối ngay bây giờ, tôi không biết bất kỳ trình duyệt nào sẽ không chấp nhận một đối tượng Arguments thực sự như đối số thứ hai .apply(). Nhưng nếu đó là một đối tượng giống Mảng như đối tượng jQuery chẳng hạn, thì có, một số trình duyệt sẽ báo lỗi

2
Câu trả lời này, khi nó xảy ra, giải quyết vấn đề sử dụng các đối tượng nâng cao để kiểm soát các video YouTube riêng lẻ được nhúng qua API Iframe của YouTube. Bạn không biết tôi đã cố gắng giải quyết thực tế là API yêu cầu nó gọi lại là một hàm toàn cục duy nhất trong bao lâu khi tôi đang cố gắng tạo một lớp để xử lý dữ liệu của mỗi video theo một cách mô-đun duy nhất. Bạn là người hùng của tôi trong ngày.
Carnix

31

trước tiên hãy lưu trữ hàm thực trong một biến ..

var oldFunction = someFunction;

sau đó xác định của riêng bạn:

someFunction = function(){
  // do something before
  oldFunction();
  // do something after
};

9
Nếu hàm của bạn là một phương thức, bạn sẽ cần sử dụng applyđể gọi nó. Xem câu trả lời của tôi.
ômomg

Nó hoạt động với tôi, nhưng cần phải thay thế someFunctionbằng window.someFunctiontrong đoạn mã trên. Lý do là hàm của tôi được khai báo bên trong $(document).ready()trình xử lý jquery .
Nelson

10

Bạn có thể tạo một hàm gọi mã của bạn, rồi gọi hàm.

var old_someFunction = someFunction;
someFunction = function(){
    alert('Hello');
    old_someFunction();
    alert('Goodbye');
}

6

Tôi không biết liệu bạn có thể cập nhật hàm hay không, nhưng tùy thuộc vào cách nó được tham chiếu, bạn có thể tạo một hàm mới ở vị trí của nó:

var the_old_function = someFunction;
someFunction = function () {
    /* ..My new code... */
    the_old_function();
    /* ..More of my new code.. */
}

5

Cũng thế. Nếu bạn muốn thay đổi ngữ cảnh cục bộ, bạn phải tạo lại hàm. Ví dụ:

var t = function() {
    var a = 1;
};

var z = function() {
    console.log(a);
};

Hiện nay

z() // => log: undefined

Sau đó

var ts = t.toString(),
    zs = z.toString();

ts = ts.slice(ts.indexOf("{") + 1, ts.lastIndexOf("}"));
zs = zs.slice(zs.indexOf("{") + 1, zs.lastIndexOf("}"));

var z = new Function(ts + "\n" + zs);

z() // => log: 1

Nhưng đây chỉ là một ví dụ đơn giản nhất. Sẽ còn rất nhiều việc để xử lý các đối số, nhận xét và trả về giá trị. Ngoài ra, vẫn còn rất nhiều cạm bẫy.
toString | lát | indexOf | lastIndexOf | chức năng mới


1

Mẫu proxy (như được sử dụng bởi user1106925) có thể được đặt bên trong một hàm. Cái tôi đã viết dưới đây hoạt động trên các hàm không có trong phạm vi toàn cầu và thậm chí trên các nguyên mẫu. Bạn sẽ sử dụng nó như thế này:

extender(
  objectContainingFunction,
  nameOfFunctionToExtend,
  parameterlessFunctionOfCodeToPrepend,
  parameterlessFunctionOfCodeToAppend
)

Trong đoạn mã dưới đây, bạn có thể thấy tôi đang sử dụng hàm để mở rộng test.prototype.doIt ().

// allows you to prepend or append code to an existing function
function extender (container, funcName, prepend, append) {

    (function() {

        let proxied = container[funcName];

        container[funcName] = function() {
            if (prepend) prepend.apply( this );
            let result = proxied.apply( this, arguments );
            if (append) append.apply( this );
            return result;
        };

    })();

}

// class we're going to want to test our extender on
class test {
    constructor() {
        this.x = 'instance val';
    }
    doIt (message) {
        console.log(`logged: ${message}`);
        return `returned: ${message}`;
    }
}

// extends test.prototype.doIt()
// (you could also just extend the instance below if desired)
extender(
    test.prototype, 
    'doIt', 
    function () { console.log(`prepended: ${this.x}`) },
    function () { console.log(`appended: ${this.x}`) }
);

// See if the prepended and appended code runs
let tval = new test().doIt('log this');
console.log(tval);

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.