Menambahkan kode ke fungsi javascript secara terprogram

114

Saya mencoba untuk menyesuaikan pustaka JS yang ada tanpa mengubah kode JS asli. Kode ini dimuat dalam beberapa file JS eksternal yang saya miliki aksesnya, dan yang ingin saya lakukan adalah mengubah salah satu fungsi yang terdapat dalam file asli tanpa menyalin dan menempel semuanya ke dalam file JS kedua.
Jadi misalnya, JS terlarang mungkin memiliki fungsi seperti ini:

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

Saya ingin bisa entah bagaimana menambahkan atau menambahkan beberapa kode JS ke dalam fungsi itu. Alasan utamanya adalah bahwa dalam JS asli yang tidak tersentuh fungsinya sangat besar dan jika JS itu diperbarui, fungsi yang saya timpa akan kedaluwarsa.

Saya tidak sepenuhnya yakin ini mungkin, tetapi saya pikir saya akan memeriksanya.

Munzilla
sumber
3
jawaban pertama ini akan membantu Anda
DarkAjax
Apakah Anda menginginkan sesuatu seperti fungsi panggilan balik?
sinemetu1

Jawaban:

220

Jika someFunctiontersedia secara global, maka Anda dapat menyimpan fungsi tersebut, membuatnya sendiri, dan meminta Anda memanggilnya.

Jadi jika ini yang asli ...

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

Anda akan melakukan ini ...

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

Ini biolanya


Perhatikan bahwa saya menggunakan .applyuntuk memanggil fungsi yang di-cache. Ini memungkinkan saya mempertahankan nilai yang diharapkan dari this, dan meneruskan argumen apa pun yang diteruskan sebagai argumen individu terlepas dari berapa banyak yang ada.

pengguna1106925
sumber
10
Jawaban ini harus benar-benar menjadi yang teratas - ini mempertahankan fungsionalitas fungsi yang dimaksud ... +1 dari saya.
Reid
17
1 untuk digunakan apply: ini adalah satu-satunya jawaban yang benar - benar menyelesaikan masalah.
lonesomeday
2
@minitech: Apa ... Anda tidak terbiasa dengan funcitonkata kunci JavaScript ? ;) Terima kasih atas pengeditannya
1
@gdoron: Saya baru saja menambahkan komentar. Kecuali saya benar-benar bingung sekarang, saya tidak tahu browser apa pun yang tidak akan menerima objek Argumen yang sebenarnya sebagai argumen kedua .apply(). Tetapi jika itu adalah objek mirip Array seperti objek jQuery misalnya, maka ya, beberapa browser akan membuat kesalahan
2
Jawaban ini, yang terjadi, memecahkan masalah penggunaan objek instan untuk mengontrol video YouTube individual yang disematkan melalui API Iframe YouTube. Anda tidak tahu sudah berapa lama saya mencoba mengatasi fakta bahwa API mengharuskan callback-nya menjadi satu fungsi global saat saya mencoba membuat kelas untuk menangani setiap data video dengan cara modular yang unik. Anda adalah pahlawan saya hari ini.
Carnix
31

pertama-tama simpan fungsi sebenarnya dalam variabel ..

var oldFunction = someFunction;

lalu tentukan sendiri:

someFunction = function(){
  // do something before
  oldFunction();
  // do something after
};
gerimis
sumber
9
Jika fungsi Anda adalah metode yang perlu Anda gunakan applyuntuk memanggilnya. Lihat jawaban saya.
hugomg
Ini berhasil untuk saya, tetapi perlu diganti someFunctiondengan window.someFunctionkode di atas. Alasannya karena fungsi saya dideklarasikan di dalam jquery $(document).ready()handler.
Nelson
10

Anda dapat membuat fungsi yang memanggil kode Anda, dan kemudian memanggil fungsi tersebut.

var old_someFunction = someFunction;
someFunction = function(){
    alert('Hello');
    old_someFunction();
    alert('Goodbye');
}
Roket Hazmat
sumber
6

Saya tidak tahu apakah Anda dapat memperbarui fungsi tersebut, tetapi bergantung pada bagaimana ini direferensikan, Anda dapat membuat fungsi baru sebagai gantinya:

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

Juga. Jika Anda ingin mengubah konteks lokal, Anda harus membuat ulang fungsi. Sebagai contoh:

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

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

Sekarang

z() // => log: undefined

Kemudian

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

Dan

z() // => log: 1

Tapi ini hanyalah contoh paling sederhana. Masih banyak pekerjaan yang harus dilakukan untuk menangani argumen, komentar, dan nilai pengembalian. Selain itu, masih banyak jebakan.
toString | mengiris | indexOf | lastIndexOf | Fungsi baru

Ivan Black
sumber
1

Pola proxy (seperti yang digunakan oleh user1106925) dapat dimasukkan ke dalam fungsi. Yang saya tulis di bawah ini berfungsi pada fungsi yang tidak dalam cakupan global, dan bahkan pada prototipe. Anda akan menggunakannya seperti ini:

extender(
  objectContainingFunction,
  nameOfFunctionToExtend,
  parameterlessFunctionOfCodeToPrepend,
  parameterlessFunctionOfCodeToAppend
)

Dalam cuplikan di bawah, Anda dapat melihat saya menggunakan fungsi untuk memperluas 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);

pwilcox.dll
sumber