Bir JavaScript işlevine programlı olarak kod ekleme


114

Orijinal JS kodunu değiştirmeden mevcut bir JS kitaplığını özelleştirmeye çalışıyorum. Bu kod, erişim hakkım olan birkaç harici JS dosyasına yüklenir ve yapmak istediğim şey, orijinal dosyadaki işlevlerden birini, her şeyi kopyalayıp ikinci JS dosyasına yapıştırmadan değiştirmektir.
Örneğin, limit dışı JS şu şekilde bir işleve sahip olabilir:

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

Bu işleve bir şekilde bazı JS kodu ekleyebilmeyi veya başına ekleyebilmeyi istiyorum. Bunun nedeni, öncelikle orijinal dokunulmaz JS'de işlevin oldukça büyük olması ve bu JS'nin güncellenmesi durumunda, üzerine yazdığım işlevin güncel olmayacağıdır.

Bunun mümkün olduğundan tam olarak emin değilim, ama kontrol edeyim dedim.


3
ilk cevap bu size yardımcı olacaktır
DarkAjax

Geri arama işlevi gibi bir şey mi istiyorsunuz?
sinemetu1

Yanıtlar:


220

Eğer someFunctionküresel kullanılabilir, o zaman, işlev önbelleğe kendi oluşturmak ve sizin diyoruz olabilir.

Yani bu orijinalse ...

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

Bunu yaparsın ...

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

İşte keman


.applyÖnbelleğe alınan işlevi çağırmak için kullandığıma dikkat edin . Bu, beklenen değerini thiskorumama ve kaç tane olduğuna bakılmaksızın bireysel argümanlar olarak iletilen argümanları iletmeme izin veriyor .


10
Bu cevap gerçekten en iyisi olmalı - söz konusu fonksiyonun işlevselliğini koruyor ... benden +1.
Reid

17
Kullanmak için +1 apply: sorunu gerçekten çözen tek cevap budur .
lonesomeday

2
@minitech: Ne ... JavaScript'in funcitonanahtar kelimesine aşina değil misiniz? ;) Düzenleme için teşekkürler

1
@gdoron: Bir yorum ekledim. Şu anda gerçekten kafam karışmadıkça, ikinci argüman olarak gerçek bir Arguments nesnesini kabul etmeyen bir tarayıcı bilmiyorum .apply(). Ancak, örneğin bir jQuery nesnesi gibi Dizi benzeri bir nesne olsaydı, evet, bazı tarayıcılar bir hata

2
Bu cevap, olduğu gibi, YouTube Iframe API'si aracılığıyla gömülü ayrı YouTube videolarını kontrol etmek için örnek nesneleri kullanma sorununu çözer. Her videonun verilerini benzersiz bir modüler yolla işlemek için bir sınıf oluşturmaya çalışırken API'nin geri aramanın tek bir global işlev olmasını gerektirdiği gerçeği etrafında ne kadar süredir çalıştığım hakkında hiçbir fikriniz yok. Sen benim kahramanımsın bugün
Carnix

31

önce gerçek işlevi bir değişkende saklayın ..

var oldFunction = someFunction;

sonra kendinizinkini tanımlayın:

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

9
İşleviniz bir yöntemse, applyonu çağırmak için kullanmanız gerekecektir . Bakın cevabım.
hugomg

Benim için çalıştı, ama değiştirmek için gerekli someFunctionolan window.someFunctionyukarıdaki kodda. Bunun nedeni, işlevimin bir jquery $(document).ready()işleyicisi içinde bildirilmiş olmasıdır .
Nelson

10

Kodunuzu çağıran ve ardından işlevi çağıran bir işlev yapabilirsiniz.

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

6

İşlevi güncelleyip güncelleyemeyeceğinizi bilmiyorum, ancak nasıl referans verildiğine bağlı olarak, onun yerine yeni bir işlev yapabilirsiniz:

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

5

Ayrıca. Yerel bağlamı değiştirmek istiyorsanız, işlevi yeniden oluşturmanız gerekir. Örneğin:

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

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

şimdi

z() // => log: undefined

Sonra

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

Ve

z() // => log: 1

Ancak bu sadece en basit örnek. Argümanlar, yorumlar ve dönüş değeri ile ilgilenmek hala çok çalışma gerektirecektir. Buna ek olarak, hala birçok tuzak var.
toString | dilim | indexOf |lastIndexOf | yeni İşlev


1

Proxy kalıbı (user1106925 tarafından kullanıldığı şekliyle) bir işlevin içine yerleştirilebilir. Aşağıda yazdığım, küresel kapsamda olmayan işlevler ve hatta prototipler üzerinde çalışıyor. Bunu şu şekilde kullanırsın:

extender(
  objectContainingFunction,
  nameOfFunctionToExtend,
  parameterlessFunctionOfCodeToPrepend,
  parameterlessFunctionOfCodeToAppend
)

Aşağıdaki kod parçacığında, test.prototype.doIt () işlevini genişletmek için kullandığımı görebilirsiniz.

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.