Jaki jest najszybszy sposób na sklonowanie funkcji w JavaScript (z jej właściwościami lub bez)?
Przychodzą mi do głowy dwie opcje eval(func.toString())
i function() { return func.apply(..) }
. Martwię się jednak o wydajność eval, a zawijanie pogorszy stos i prawdopodobnie pogorszy wydajność, jeśli zostanie zastosowany dużo lub zastosowany do już zapakowanego.
new Function(args, body)
wygląda ładnie, ale jak dokładnie mogę niezawodnie podzielić istniejącą funkcję na argumenty i ciało bez parsera JS w JS?
Z góry dziękuję.
Aktualizacja: Mam na myśli to, że mogę to zrobić
var funcB = funcA.clone(); // where clone() is my extension
funcB.newField = {...}; // without affecting funcA
javascript
function
Andrey Shchekin
źródło
źródło
Odpowiedzi:
Spróbuj tego:
źródło
Oto zaktualizowana odpowiedź
Jednak
.bind
jest to nowoczesna (> = iE9) funkcja JavaScript (z obejściem zgodności z MDN )Uwagi
To nie sklonować obiektem Function dołączone dodatkowe właściwości , łącznie z prototypem nieruchomości. Podziękowania dla @jchook
Nowa funkcja ta zmienna utknęła z argumentem podanym w funkcji bind (), nawet przy nowych wywołaniach funkcji apply (). Kredyt dla @Kevin
źródło
newFunc
NIE będzie miał własnego prototypu dlanew newFunc
instancji, podczas gdyoldFunc
będzie.var f = function() { console.log('hello ' + this.name) }
gdy jest przypisany do{name: 'Bob'}
drukowania „cześć Bob”.f.apply({name: 'Sam'})
wypisze również „hello Bob”, ignorując obiekt „this”.function () { [native code] }
zamiast pełnej zawartości funkcji.Oto nieco lepsza wersja odpowiedzi Jareda. Ten nie będzie miał głęboko zagnieżdżonych funkcji, im więcej klonujesz. Zawsze nazywa oryginał.
Ponadto, w odpowiedzi na zaktualizowaną odpowiedź udzieloną przez pico.creator, warto zauważyć, że
bind()
funkcja dodana w Javascript 1.8.5 ma ten sam problem co odpowiedź Jareda - będzie się zagnieżdżać, powodując coraz wolniejsze funkcje za każdym razem, gdy zostanie użyta.źródło
Jest ciekawy, ale nadal nie można znaleźć odpowiedzi na temat wydajności powyższe pytanie, napisałem to sens dla nodejs przetestować zarówno wydajność i niezawodność wszystkich prezentowanych (i goli) rozwiązań.
Porównałem czasy tworzenia funkcji klonowania i wykonywania klonów. Wyniki wraz z błędami asercji są zawarte w komentarzu do istoty.
Plus moje dwa grosze (na podstawie sugestii autora):
clone0 cent (szybszy, ale brzydszy):
clone4 cent (wolniej, ale dla tych, którzy nie lubią eval () do celów znanych tylko im i ich przodkom):
Jeśli chodzi o wydajność, jeśli eval / new Function jest wolniejsze niż rozwiązanie wrapper (i naprawdę zależy to od rozmiaru ciała funkcji), daje ci klon czystej funkcji (i mam na myśli prawdziwy płytki klon z właściwościami, ale stanem niewspółdzielonym) bez niepotrzebnego rozmycia z ukrytymi właściwościami, funkcjami opakowania i problemami ze stosem.
Ponadto zawsze jest jeden ważny czynnik, który należy wziąć pod uwagę: im mniej kodu, tym mniej miejsc na błędy.
Wadą korzystania z funkcji eval / new jest to, że klon i oryginalna funkcja będą działać w różnych zakresach. Nie będzie działać dobrze z funkcjami, które używają zmiennych o określonym zakresie. Rozwiązania wykorzystujące zawijanie podobne do wiązania są niezależne od zakresu.
źródło
Object.assign(newfun.prototype, this.prototype);
przed instrukcją return (czysta wersja), Twoja metoda jest najlepszą odpowiedzią.Uruchomienie tej metody było dość ekscytujące, więc tworzy ona klon funkcji przy użyciu wywołania funkcji.
Niektóre ograniczenia dotyczące domknięć opisane w Dokumentacji funkcji MDN
Cieszyć się.
źródło
Krótko i prosto:
źródło
źródło
źródło
originalFunction
, ale w rzeczywistości nie spowoduje ich wykonania podczas uruchamianiaclonedFunction
, co jest nieoczekiwane.Ta odpowiedź jest dla osób, które postrzegają klonowanie funkcji jako odpowiedź na ich pożądane użycie, ale wielu z nich w rzeczywistości nie musi klonować funkcji, ponieważ tak naprawdę chcą mieć możliwość dołączania różnych właściwości do tej samej funkcji, ale tylko zadeklaruj tę funkcję raz.
Zrób to, tworząc funkcję tworzącą funkcję:
To nie jest dokładnie to samo, co opisałeś, jednak zależy to od tego, jak chcesz użyć funkcji, którą chcesz sklonować. Zużywa to również więcej pamięci, ponieważ w rzeczywistości tworzy wiele kopii funkcji, raz na wywołanie. Jednak ta technika może rozwiązać przypadek użycia niektórych osób bez potrzeby stosowania skomplikowanej
clone
funkcji.źródło
Zastanawiam się tylko - dlaczego miałbyś chcieć klonować funkcję, skoro masz prototypy ORAZ możesz ustawić zakres wywołania funkcji na cokolwiek chcesz?
źródło
Jeśli chcesz utworzyć klon za pomocą konstruktora Function, powinno działać coś takiego:
Prosty test:
Te klony stracą jednak swoje nazwy i zakres dla wszelkich zamkniętych zmiennych.
źródło
Poprawiłem odpowiedź Jareda na swój własny sposób:
1) teraz obsługuje klonowanie konstruktorów (można wywołać z new); w takim przypadku pobiera tylko 10 argumentów (można to zmieniać) - ze względu na niemożność przekazania wszystkich argumentów w oryginalnym konstruktorze
2) wszystko jest prawidłowo zamknięte
źródło
arguments[0], arguments[1] /*[...]*/
dlaczego po prostu nie używasz...arguments
? 1) Nie ma zależności co do ilości argumentów (tutaj ograniczona do 10) 2) krócejChociaż nigdy nie polecałbym tego używać, pomyślałem, że byłoby ciekawym małym wyzwaniem wymyślenie bardziej precyzyjnego klonu, biorąc niektóre z praktyk, które wydawały się najlepsze, i trochę je poprawiając. Oto wynik logów:
źródło
Ta funkcja klonowania:
Zauważ, że ta wersja wykonuje tylko krótką kopię. Jeśli funkcja ma obiekty jako właściwości, to zachowane zostaje odwołanie do oryginalnego obiektu (to samo zachowanie, co obiekt rozkładówka lub obiekt. Oznacza to, że zmiana głębokich właściwości w sklonowanej funkcji wpłynie na obiekt, do którego odwołuje się oryginalna funkcja!
źródło