Komentarze Alana Storma w odpowiedzi na moją odpowiedź dotyczącą with
oświadczenia skłoniły mnie do myślenia. Rzadko znajdowałem powód do korzystania z tej konkretnej funkcji języka i nigdy nie zastanawiałem się, w jaki sposób może to powodować problemy. Teraz jestem ciekawy, w jaki sposób mogę skutecznie wykorzystać with
, unikając pułapek.
Gdzie znalazłeś with
stwierdzenie przydatne?
with
więc nie ma już czegoś takiego.Odpowiedzi:
Dzisiaj przyszło mi do głowy inne zastosowanie, więc podekscytowałem się w Internecie i znalazłem wzmiankę o nim: Definiowanie zmiennych w zakresie zakresu .
tło
JavaScript, pomimo powierzchownego podobieństwa do C i C ++, nie obejmuje zmiennych do bloku, w którym są zdefiniowane:
Zadeklarowanie zamknięcia w pętli jest częstym zadaniem, które może prowadzić do błędów:
Ponieważ pętla for nie wprowadza nowego zakresu, to samo
num
- z wartością2
- będzie współdzielone przez wszystkie trzy funkcje.Nowy zakres:
let
iwith
Wraz z wprowadzeniem
let
oświadczenia w ES6 łatwo jest wprowadzić nowy zakres, gdy jest to konieczne, aby uniknąć tych problemów:Lub nawet:
Dopóki ES6 nie będzie powszechnie dostępny, użycie to pozostaje ograniczone do najnowszych przeglądarek i programistów chętnych do korzystania z transpilerów. Możemy jednak łatwo zasymulować to zachowanie, używając
with
:Pętla działa teraz zgodnie z przeznaczeniem, tworząc trzy oddzielne zmienne o wartościach od 0 do 2. Zauważ, że zmienne zadeklarowane w bloku nie mają do niego zasięgu , w przeciwieństwie do zachowania bloków w C ++ (w C, zmienne muszą być deklarowane na początku blok, więc w pewnym sensie jest podobny). To zachowanie jest w rzeczywistości dość podobne do
let
składni blokowej wprowadzonej we wcześniejszych wersjach przeglądarek Mozilla, ale nie jest powszechnie stosowane gdzie indziej.źródło
for (var i = 0; i < 3; ++i) { setTimeout ((function () { var num = i; return function () { alert (num); }; }) (), 10);}
var toString = function () { return "Hello"; }; with ({"test":1}) { console.log(toString()); };
. W zakres tego z oświadczeniem toString () jest dziedziczną własność obiektu , tak wyraźnie określona funkcja nie jest tzw. Nadal świetna odpowiedź :-)Używam instrukcji with jako prostej formy importu o określonym zakresie. Powiedzmy, że masz jakiś konstruktor znaczników. Zamiast pisać:
Zamiast tego możesz napisać:
W tym przypadku użycia nie wykonuję żadnego zadania, więc nie mam z tym problemu dwuznaczności.
źródło
context.bezierCurveTo
sto razy prosto, możesz powiedzieć,var bc2 = context.bezierCurveTo;
a następnie po prostu iść zabc2(x,x,etc);
każdym razem, gdy chcesz to nazwać. To dość szybkie i jeszcze mniej gadatliwe, a jednocześniewith
bardzo wolne.Jak wskazały moje poprzednie komentarze, nie sądzę, abyś mógł
with
bezpiecznie korzystać z niego, bez względu na to, jak kuszące może być w danej sytuacji. Ponieważ problem nie jest tutaj bezpośrednio omawiany, powtórzę go. Rozważ następujący kodBez dokładnego zbadania tych wywołań funkcji nie można w żaden sposób powiedzieć, jaki będzie stan programu po uruchomieniu tego kodu. Gdyby
user.name
było już ustawione, teraz będzieBob
. Jeśli nie zostanie ustawiony, globalnyname
zostanie zainicjowany lub zmieniony na,Bob
auser
obiekt pozostanie bezname
właściwości.Błędy się zdarzają. Jeśli użyjesz go razem , w końcu to zrobisz i zwiększysz szanse, że Twój program się nie powiedzie. Co gorsza, możesz napotkać działający kod, który ustawia globalny blok w bloku, celowo lub przez autora, który nie wie o tym dziwactwie konstrukcji. Przypomina to napotkanie przełącznika, nie masz pojęcia, czy autor tego zamierzał, i nie ma sposobu, aby dowiedzieć się, czy „naprawienie” kodu spowoduje regresję.
Nowoczesne języki programowania są pełne funkcji. Niektóre funkcje po latach użytkowania okazały się złe i należy ich unikać. Javascript
with
jest jednym z nich.źródło
with
Ostatnio stwierdzenie to okazało się niezwykle przydatne. Ta technika nigdy tak naprawdę nie przyszła mi do głowy, dopóki nie rozpocząłem bieżącego projektu - konsoli wiersza poleceń napisanej w JavaScript. Próbowałem emulować interfejsy API Firebug / WebKit, w których można wprowadzać specjalne polecenia do konsoli, ale nie zastępują one żadnych zmiennych w zasięgu globalnym. Pomyślałem o tym, próbując przezwyciężyć problem, o którym wspomniałem w komentarzach do doskonałej odpowiedzi Shog9 .Aby osiągnąć ten efekt, użyłem dwóch z instrukcjami do „warstwowania” zakresu za zasięgiem globalnym:
Wspaniałą rzeczą w tej technice jest to, że oprócz wad wydajnościowych nie odczuwa ona zwykłych obaw
with
wyrażenia, ponieważ i tak oceniamy w zakresie globalnym - nie istnieje niebezpieczeństwo, że zmienne poza naszym pseudo-zasięgiem będą zmodyfikowany.Zainspirowałem się opublikowaniem tej odpowiedzi, gdy, ku mojemu zaskoczeniu, udało mi się znaleźć tę samą technikę, która była używana w innym miejscu - kod źródłowy Chromium !
EDYCJA: Właśnie sprawdziłem źródło Firebug, łączą 4 z instrukcjami razem, aby uzyskać jeszcze więcej warstw. Zwariowany!
źródło
Tak, tak i tak. Istnieje bardzo uzasadnione użycie. Zegarek:
Zasadniczo wszelkie inne haki DOM lub CSS są fantastyczne w użyciu. To nie jest tak, że „CloneNode” będzie niezdefiniowany i wróci do globalnego zasięgu, chyba że zejdziesz mu z drogi i nie zdecydujesz się na to.
Skarga prędkości Crockforda polega na tym, że za pomocą tworzy się nowy kontekst. Konteksty są na ogół drogie. Zgadzam się. Ale jeśli właśnie utworzyłeś div i nie masz pod ręką jakiegoś frameworka do ustawiania css i musisz ręcznie skonfigurować około 15 właściwości CSS, wówczas tworzenie kontekstu będzie prawdopodobnie tańsze niż tworzenie zmiennych i 15 dereferencji:
itp...
źródło
with
. Jednak w tym konkretnym przypadku możesz po prostu:element.style.cssText="background: black ; color: blue ; border: 1px solid green"
extend
sposobu z obu jQuery lub underscore.js:$.extend(element.style, {fontWeight: 'bold', fontSize: '1.5em', color: '#55d', marginLeft: '2px'})
..css()
metody ...Możesz zdefiniować funkcję małego pomocnika, aby zapewnić korzyści
with
bez niejasności:źródło
with_
będąc błotnistą podwójną wersją(function(_){ _.a="foo"; })(object_here);
(standardowego sposobu symulowania bloków w stylu c / java). Użyj tego zamiast tego.Nie wydaje się to opłacalne, ponieważ możesz wykonać następujące czynności:
źródło
with
.Nigdy nie używam, nie widzę powodu i nie polecam tego.
Problem
with
polega na tym, że zapobiega wielu optymalizacjom leksykalnym może wykonać implementacja ECMAScript. Biorąc pod uwagę rozwój szybkich silników opartych na JIT, problem ten prawdopodobnie stanie się jeszcze ważniejszy w najbliższej przyszłości.Może to wyglądać na
with
dopuszczenie czystszych konstrukcji (np. Wprowadzenie nowego zakresu zamiast zwykłego anonimowego opakowania funkcji lub zastąpienie pełnego aliasingu), ale tak naprawdę nie jest tego warte . Oprócz zmniejszonej wydajności zawsze istnieje niebezpieczeństwo przypisania do właściwości niewłaściwego obiektu (gdy właściwość nie zostanie znaleziona na obiekcie we wstrzykiwanym zakresie) i być może błędnego wprowadzenia zmiennych globalnych. IIRC, ta ostatnia kwestia motywuje Crockforda do zalecania unikania gowith
.źródło
with(){}
konstrukcji takich jak te podane w innych odpowiedziach tutaj, w nowoczesnych przeglądarkach, chciałbym zobaczyć im!with(){}
: skonfigurowanie nowego zakresu za pomocąwith
jest niezwykle drogie w każdej testowanej przeze mnie przeglądarce. Chciałbyś tego uniknąć w każdym często wywoływanym kodzie. Ponadto Chrome okazał się dramatycznym hitem dla każdego kodu wykonywanego wwith()
zakresie. Co ciekawe, IE miał najlepszą charakterystykę wydajności kodu wwith()
blokach: uwzględnienie kosztu instalacji,with()
zapewnia najszybszy sposób dostępu członka do maszyn wirtualnych IE6 i IE8 (choć ogólnie te maszyny wirtualne są najwolniejsze). Dobre rzeczy, dzięki ...with()
Chrome jest prawie o rząd wielkości wolniejszy i ponad dwukrotnie szybszy w IE ...!Visual Basic.NET ma podobną
With
instrukcję. Jednym z bardziej powszechnych sposobów, w jaki go używam, jest szybkie ustawienie szeregu właściwości. Zamiast:, Umiem pisać:
To nie jest tylko kwestia lenistwa. Dzięki temu kod jest znacznie bardziej czytelny. I w przeciwieństwie do JavaScript, nie ma w tym dwuznaczności, ponieważ musisz poprzedzić wszystko, na co wpływa instrukcja,
.
kropką. Tak więc następujące dwa są wyraźnie odrębne:vs.
Pierwsza to
someObject.Foo
; ten drugi jestFoo
objęty zakresem zewnętrznymsomeObject
.Uważam, że brak rozróżnienia w JavaScript sprawia, że jest on znacznie mniej przydatny niż wariant Visual Basic, ponieważ ryzyko niejednoznaczności jest zbyt wysokie. Poza tym
with
nadal jest potężnym pomysłem, który może poprawić czytelność.źródło
Możesz użyć
with
do wprowadzenia zawartości obiektu jako zmiennych lokalnych do bloku, tak jak dzieje się to za pomocą tego małego silnika szablonów .źródło
Użycie „with” może sprawić, że kod będzie bardziej suchy.
Rozważ następujący kod:
Możesz go wysuszyć w następujący sposób:
Myślę, że zależy to od tego, czy wolisz czytelność czy ekspresję.
Pierwszy przykład jest bardziej czytelny i prawdopodobnie zalecany dla większości kodów. Ale i tak większość kodu jest dość oswojona. Drugi jest nieco bardziej niejasny, ale wykorzystuje ekspresyjną naturę języka, aby zmniejszyć rozmiar kodu i zbędne zmienne.
Wyobrażam sobie, że ludzie, którzy lubią Javę lub C #, wybiorą pierwszy sposób (object.member), a ci, którzy wolą Ruby lub Python, wybiorą ten drugi sposób.
źródło
Myślę, że oczywistym zastosowaniem jest skrót. Jeśli np. Inicjujesz obiekt, po prostu zapisujesz dużo „ObjectName”. Coś w rodzaju „with-slots” lisp, które pozwalają pisać
co jest tym samym, co pisanie
Bardziej oczywiste jest, dlaczego jest to skrót, kiedy twój język pozwala na „Objectname.foo”, ale nadal.
źródło
with-slots
wymaga określenia, których gniazd używasz, podczas gdywith
użyjesz tych gniazd, które zostaną powiązane w czasie wykonywania.Mając doświadczenie z Delphi, powiedziałbym, że używanie z powinno być ostateczną optymalizacją rozmiaru, prawdopodobnie wykonaną przez pewnego rodzaju algorytm minimalizujący javascript z dostępem do statycznej analizy kodu w celu weryfikacji jego bezpieczeństwa.
Problemy z określaniem zakresu, które możesz napotkać przy swobodnym używaniu instrukcji with , mogą być ogromnym bólem w ** i nie chciałbym, aby ktokolwiek przeżył sesję debugowania, aby dowiedzieć się, co on .. dzieje się w twoim kodzie , aby dowiedzieć się, że przechwycił element członkowski lub niepoprawną zmienną lokalną zamiast zamierzonej zmiennej globalnej lub zewnętrznej.
VB z instrukcją jest lepszy, ponieważ potrzebuje kropek, aby ujednoznacznić zakres, ale Delphi z instrukcją to naładowana broń z wyzwalaczem do włosów i wydaje mi się, że javascript jest wystarczająco podobny, aby uzasadnić to samo ostrzeżenie.
źródło
Używanie z nie jest zalecane i jest zabronione w trybie ścisłym ECMAScript 5. Zalecaną alternatywą jest przypisanie obiektu, którego właściwości chcesz uzyskać dostęp do zmiennej tymczasowej.
Źródło: Mozilla.org
źródło
Za pomocą instrukcji with można zmniejszyć rozmiar kodu lub dla członków klasy prywatnej, na przykład:
Instrukcja with jest bardzo przydatna, jeśli chcesz zmodyfikować zakres, co jest niezbędne do posiadania własnego zakresu globalnego, którym możesz manipulować w czasie wykonywania. Możesz nałożyć stałe lub niektóre często używane funkcje pomocnicze, takie jak np. „ToUpper”, „toLower” lub „isNumber”, „clipNumber” aso ..
O złej wydajności, którą często czytam: Określanie zakresu funkcji nie będzie miało żadnego wpływu na wydajność, w rzeczywistości w moim FF funkcja o zasięgu działa szybciej niż nieskalowana:
Tak więc w wyżej wspomniany sposób użyta instrukcja with nie ma negatywnego wpływu na wydajność, ale jest dobra, ponieważ zmniejsza rozmiar kodu, co wpływa na użycie pamięci na urządzeniach mobilnych.
źródło
Używanie z powoduje również spowolnienie kodu w wielu implementacjach, ponieważ wszystko jest teraz zawinięte w dodatkowy zakres wyszukiwania. Nie ma uzasadnionego powodu do używania w JavaScript.
źródło
var obj={a:0,b:0,c:0};var d=+new Date;with(obj){for(var i=0;i<1000000;++i){a+=1;b+=1;c+=1}}+new Date-d;
daje średnio 2500, podczas gdyvar obj={a:0,b:0,c:0};var d=+new Date;for(var i=0;i<1000000;++i){obj.a+=1;obj.b+=1;obj.c+=1}+new Date-d;
daje średnio 750, co sprawia, że ten używa ponad 3 razy wolniej.with
kodu i 903 bez. Z tą niewielką różnicą, nawet w ciasnej pętli, dokonałbym wyboru opartego na prostocie kodowania i łatwości refaktoryzacji dla poszczególnych przypadków, zanim martwię się o wydajność.Myślę, że instrukcja with może się przydać podczas konwersji języka szablonów na JavaScript. Na przykład JST w base2 , ale widziałem to częściej.
Zgadzam się, że można to zaprogramować bez oświadczenia o rezygnacji. Ponieważ jednak nie powoduje żadnych problemów, jest to zgodne z prawem użycie.
źródło
Jest dobry do umieszczania kodu, który działa w stosunkowo skomplikowanym środowisku, w kontenerze: używam go do tworzenia lokalnego powiązania dla „okna” i do uruchamiania kodu przeznaczonego dla przeglądarki internetowej.
źródło
Myślę, że dosłowne użycie obiektu jest interesujące, jak drop-in zamiast użycia zamknięcia
lub z oświadczeniem równoważnym zamknięcia
Myślę, że prawdziwym ryzykiem jest przypadkowe zminimalizowanie zmiennych, które nie są częścią instrukcji with, dlatego podoba mi się przekazanie dosłowności obiektu, możesz zobaczyć dokładnie, co będzie w dodanym kontekście w kodzie.
źródło
Stworzyłem funkcję „scalania”, która eliminuje niektóre z tych dwuznaczności w
with
instrukcji:Mogę go używać podobnie
with
, ale wiem, że nie wpłynie to na żaden zakres, na który nie mam wpływu.Stosowanie:
źródło
Dla niektórych krótkich kawałków kodu, chciałbym skorzystać z funkcji trygonometrycznych jak
sin
,cos
itd. W trybie stopni zamiast w trybie promienistej. W tym celu używamAngularDegree
obiektu:Następnie mogę używać funkcji trygonometrycznych w trybie stopniowym bez dalszego szumu językowego w
with
bloku:Oznacza to: Używam obiektu jako zbioru funkcji, które włączam w ograniczonym regionie kodu dla bezpośredniego dostępu. Uważam to za przydatne.
źródło
with
instrukcji w ten sposób, po prostu utrudnia odczytanie kodu, ponieważ nie wiesz, która funkcja jest globalna, a która funkcja jest wywoływana w zakresie z obiektem, więc jeśli jakakolwiek funkcja nie została zdefiniowana w zakres obiektu, a następnie spróbuje uzyskać do niego dostęp w globalnej przestrzeni nazwz = Math.atan2( Math.sin(d * Math.PI / 180), Math.cos( pol.lat * Math.PI / 180) * Math.tan( pos.lat * Math.PI / 180 ) - Math.sin( pol.lat * Math.PI / 180 ) * Math.cos( d * Math.PI / 180) ) * 180 / Math.PI;
dałaby ten sam rezultat, ale to horror.with
które by Cię zaskoczyły.Myślę, że użyteczność
with
może zależeć od tego, jak dobrze napisany jest twój kod. Na przykład, jeśli piszesz kod, który wygląda następująco:możesz argumentować, że
with
poprawi to czytelność kodu, wykonując następujące czynności:I odwrotnie, można argumentować, że naruszasz Prawo Demeter , ale z drugiej strony może nie. I dygresję =).
Przede wszystkim wiedz, że Douglas Crockford nie zaleca używania
with
. Zachęcam do zapoznania się z jego postem na bloguwith
i jego alternatywami tutaj .źródło
Po prostu nie rozumiem, w jaki sposób używanie z jest bardziej czytelne niż pisanie object.member. Nie sądzę, że jest mniej czytelny, ale nie sądzę, żeby był bardziej czytelny.
Jak powiedział lassevk, zdecydowanie mogę zobaczyć, w jaki sposób używanie z byłoby bardziej podatne na błędy niż używanie bardzo wyraźnej składni „object.member”.
źródło
Sprawdzanie poprawności formularza w javascript na W3schools http://www.w3schools.com/js/js_form_validation.asp, gdzie formularz obiektu jest „skanowany” w celu znalezienia danych wejściowych o nazwie „email”
Ale zmodyfikowałem go, aby uzyskać z KAŻDEJ formy wszystkie pola sprawdzane jako niepuste, niezależnie od nazwy lub ilości pól w formularzu. Cóż, przetestowałem tylko pola tekstowe.
Ale with () uprościło sprawę. Oto kod:
źródło
Widelec Coco w CoffeeScript ma
with
słowo kluczowe, ale po prostu ustawiathis
(także zapisywalny jak@
w CoffeeScript / Coco) na obiekt docelowy w bloku. Eliminuje to niejednoznaczność i osiąga zgodność z trybem ścisłym ES5:źródło
Oto dobre zastosowanie
with
: dodawanie nowych elementów do literału obiektu, na podstawie wartości przechowywanych w tym obiekcie. Oto przykład, którego właśnie użyłem dzisiaj:Miałem zestaw możliwych płytek (z otworami skierowanymi do góry, dołu, lewej lub prawej), które można wykorzystać, i chciałem szybko dodać listę płytek, które zawsze będą umieszczane i blokowane na początku gry . Nie chciałem pisać dalej
types.tbr
dla każdego typu na liście, więc po prostu użyłemwith
.źródło
Możesz użyć z, aby uniknąć konieczności jawnego zarządzania arity podczas korzystania z pliku.j.j:
Wdrożenie Requirej.declare:
źródło
Jak zauważył Andy E. w komentarzach do odpowiedzi Shog9, to potencjalnie nieoczekiwane zachowanie występuje podczas używania
with
z literałem obiektu:Nie to, że nieoczekiwane zachowanie nie było już znakiem rozpoznawczym
with
.Jeśli nadal chcesz używać tej techniki, przynajmniej użyj obiektu z zerowym prototypem.
Ale to zadziała tylko w ES5 +. Nie używaj też
with
.źródło
Pracuję nad projektem, który umożliwi użytkownikom przesyłanie kodu w celu zmodyfikowania zachowania części aplikacji. W tym scenariuszu używam
with
klauzuli, aby ich kod nie modyfikował niczego poza zakresem, z którym chciałbym, aby się z nimi bałaganili. (Uproszczona) część kodu, której używam do tego celu:Ten kod zapewnia (w pewnym stopniu), że kod zdefiniowany przez użytkownika nie ma dostępu do żadnych obiektów o globalnym zasięgu, takich jak
window
żadna z moich lokalnych zmiennych poprzez zamknięcie.Mówiąc krótko, wciąż muszę przeprowadzać statyczne sprawdzanie kodu przesłanego przez użytkownika, aby upewnić się, że nie używają innych podstępnych sposobów uzyskiwania dostępu do zasięgu globalnego. Na przykład następujący kod zdefiniowany przez użytkownika pobiera bezpośredni dostęp do
window
:źródło
Mój
sprowadza się do
Czy możesz zaufać tak niskiej jakości kodowi? Nie, widzimy, że stało się absolutnie nieczytelne. Ten przykład niezaprzeczalnie udowadnia, że nie ma potrzeby deklaracji rezygnacji, jeśli poprawię czytelność;)
źródło