JavaScript'in otomatik noktalı virgül ekleme (ASI) için kurallar nelerdir?


445

Öncelikle, bunun tarayıcıya bağlı olup olmadığını sormalıyım.

Geçersiz bir belirteç bulunursa, ancak kod bölümünün bu geçersiz belirteç kadar geçerli olduğunu okudum, bir satır sonu ile önce belirteç önce bir noktalı virgül eklenir.

Bununla birlikte, noktalı virgül eklemenin neden olduğu hatalar için belirtilen yaygın örnek:

return
  _a+b;

..a, geçerli bir jeton olacağından bu kurala uymuyor gibi görünüyor.

Öte yandan, çağrı zincirlerini kırmak beklendiği gibi çalışıyor:

$('#myButton')
  .click(function(){alert("Hello!")});

Kuralların daha ayrıntılı bir açıklaması olan var mı?


22
Orada olan bir Spec ...
Miles

33

3
Bkz. S. 26. yukarıda belirtilen PDF.
ᴠɪɴᴄᴇɴᴛ


bölüm 11.9 Otomatik Noktalı virgül yerleştirme
Andrew Lam

Yanıtlar:


454

Her şeyden önce, otomatik noktalı virgül eklemeden hangi ifadelerin etkilendiğini bilmelisiniz (kısaca ASI olarak da bilinir):

  • boş açıklama
  • var Beyan
  • ifade ifadesi
  • do-while Beyan
  • continue Beyan
  • break Beyan
  • return Beyan
  • throw Beyan

ASI'nın somut kuralları §11.9.1 Otomatik Noktalı virgül yerleştirme kuralları spesifikasyonunda açıklanmıştır.

Üç vaka tanımlanmıştır:

  1. Dilbilgisi tarafından izin verilmeyen bir belirteçle ( LineTerminatorveya }) karşılaşıldığında, şu durumlarda önüne noktalı virgül eklenir:

    • Jeton, önceki jetondan en az bir tane ile ayrılır LineTerminator.
    • Belirteç }

    örneğin :

    { 1
    2 } 3

    dönüştü

    { 1
    ;2 ;} 3;

    NumericLiteral 1İlk durum, bir hat sonlandırıcı token aşağıdaki karşılamaktadır. İkinci durum, token aşağıdaki karşılamaktadır .
    2}

  2. Belirteçlerin giriş akışının sonuna rastlandığında ve ayrıştırıcı giriş belirteci akışını tek bir tam Program olarak ayrıştıramadığında, giriş akışının sonuna otomatik olarak noktalı virgül eklenir.

    örneğin :

    a = b
    ++c

    şu biçime dönüştürülür:

    a = b;
    ++c;
  3. Bu durum, bir gramer dilbilgisi üretimi tarafından izin verildiğinde ortaya çıkar, ancak üretim sınırlı bir üretimdir olduğu durumlarda, sınırlı işaretin önüne otomatik olarak bir noktalı virgül yerleştirilir.

    Kısıtlı yapımlar:

    UpdateExpression :
        LeftHandSideExpression [no LineTerminator here] ++
        LeftHandSideExpression [no LineTerminator here] --
    
    ContinueStatement :
        continue ;
        continue [no LineTerminator here] LabelIdentifier ;
    
    BreakStatement :
        break ;
        break [no LineTerminator here] LabelIdentifier ;
    
    ReturnStatement :
        return ;
        return [no LineTerminator here] Expression ;
    
    ThrowStatement :
        throw [no LineTerminator here] Expression ; 
    
    ArrowFunction :
        ArrowParameters [no LineTerminator here] => ConciseBody
    
    YieldExpression :
        yield [no LineTerminator here] * AssignmentExpression
        yield [no LineTerminator here] AssignmentExpression

    Klasik örnek ReturnStatement:

    return 
      "something";

    dönüştü

    return;
      "something";

4
# 1: Dilbilgisi tarafından izin verilmeyen jeton genellikle satır sonlandırıcı değil, değil mi (3 numaralı kısıtlı yapımları kastetmedikçe)? Parantezleri atlamanız gerektiğini düşünüyorum. # 2 Örnek ++c, netlik sağlamak için yalnızca sonrasının eklenmesini göstermemelidir ?
Bergi

3
ASI aslında bir motorun ayrıştırıcısında deyimi sonlandırmak için aslında "noktalı virgül eklemek" gerekmediğini unutmayın ...
Nisan

1
"girdi akışı" ne diyorsa, bu "satır" anlamına mı geliyor? "Giriş jetonu akışı" anlaşılması biraz zorlaşıyor
nonopolarity

Spesifikasyon bağlantısı başkası için çalışıyor mu? Beni, üzerinde ölü bir bağlantı bulunan neredeyse boş bir sayfaya götürdü.
intcreator

lütfen bu kurallara göre, "a [LineBreak] = [LineBreak] 3" ifadesinin 太極 者 無極 而 生 örneğinin nasıl çalıştığını açıklayın
Nir O.

45

Doğrudan ECMA-262, Beşinci Baskı ECMAScript Özellikleri :

7.9.1 Otomatik Noktalı virgül yerleştirme kuralları

Noktalı virgül yerleştirmenin üç temel kuralı vardır:

  1. Program soldan sağa ayrıştırılırken , dilbilgisinin herhangi bir üretimi tarafından izin verilmeyen bir jetonla ( rahatsız edici jeton olarak adlandırılır ) karşılaşıldığında, aşağıdakilerden biri veya daha fazlası varsa, ihlal jetonuna otomatik olarak bir noktalı virgül yerleştirilir. koşullar doğrudur:
    • Sorun teşkil eden belirteç, önceki belirteçten en az bir tane ile ayrılır LineTerminator .
    • Sorun yaratan jeton }.
  2. Program soldan sağa ayrıştırılırken, belirteçlerin giriş akışının sonu ile karşılaşıldığında ve ayrıştırıcı giriş belirteci akışını tek bir tam ECMAScript olarak ayrıştıramadığında Program , otomatik olarak programın sonuna bir noktalı virgül eklenir. girdi akışı.
  3. Program soldan sağa ayrıştırılırken, bazı dilbilgisi üretiminin izin verdiği bir belirteçle karşılaşıldığında, ancak üretim sınırlı bir üretimdir ve belirteç, ek açıklamadan hemen sonra bir terminal veya terminal olmayan ilk belirteç olur Kısıtlı üretim içinde " [ LineTerminatorburada yok ] " (ve bu nedenle böyle bir jetona kısıtlı jeton adı verilir) ve kısıtlı jeton, önceki jetondan en az bir LineTerminator tarafından ayrılır , ardından kısıtlı jetondan önce otomatik olarak bir noktalı virgül eklenir.

Bununla birlikte, yukarıdaki kurallarda ek bir geçersiz kılma koşulu vardır: noktalı virgül boş bir deyim olarak ayrıştırılırsa veya bu noktalı virgül bir başlığın iki noktalı virgülünden biri haline gelirse asla noktalı virgül otomatik olarak eklenmez. for ifadenin (bkz. 12.6) .3).


44

Spesifikasyonlardaki bu 3 kuralı çok iyi anlayamadım - daha sade bir İngilizceye sahip olmayı umuyorum - ama işte JavaScript'ten topladığım şey: Kesin Rehber, 6. Baskı, David Flanagan, O'Reilly, 2011:

Alıntı:

JavaScript her satır sonunu noktalı virgül olarak işlemez: yalnızca satır kesmelerini yalnızca noktalı virgül olmadan kodu ayrıştıramadığında noktalı virgül olarak kabul eder.

Başka bir alıntı: kod için

var a
a
=
3 console.log(a)

JavaScript ikinci satır sonunu noktalı virgül olarak değerlendirmez, çünkü a = 3 uzun ifadesini ayrıştırmaya devam edebilir;

ve:

JavaScript'in ikinci satırı ilk satırdaki ifadenin devamı olarak ayrıştıramadığı durumlarda satır sonlarını noktalı virgül olarak yorumladığı genel kuralın iki istisnası. İlk istisna, return, break ve continue ifadelerini içerir

... Bu kelimelerden herhangi birinden sonra satır sonu görünüyorsa JavaScript her zaman satır sonunu noktalı virgül olarak yorumlar.

... İkinci istisna ++ ve −− işleçlerini içerir ... Bu işleçlerden herhangi birini postfix işleçleri olarak kullanmak istiyorsanız, geçerli oldukları ifadeyle aynı satırda görünmeleri gerekir. Aksi takdirde, satır sonu noktalı virgül olarak ele alınır ve ++ veya -, aşağıdaki koda uygulanan önek operatörü olarak ayrıştırılır. Bu kodu düşünün, örneğin:

x 
++ 
y

Olarak x; ++y;değil , ayrıştırılırx++; y

Yani basitleştirmeyi düşünüyorum, yani:

(1) Bazı anahtar kelimeler gibi sonra: 2 olgu hariç - Genel olarak, JavaScript uzun mantıklı gibi kod devamı olarak ele alacaktır return, break, continueve bu görürse (2) ++ya da --yeni bir hat üzerinde, o zaman katacak ;bir önceki satırın sonunda.

"Bu, mantıklı olduğu sürece kodun devamı olarak ele alın" bölümü düzenli ifadenin açgözlü eşleşmesi gibi hissettiriyor.

Yukarıda belirtilenlerle birlikte, bu returnsatır kesmesi anlamına gelir , JavaScript yorumlayıcı bir;

(tekrar alıntı: Bu kelimelerden herhangi birinde bir satır sonu görünüyorsa [ör. return ] ... JavaScript her zaman satır sonunu noktalı virgül olarak yorumlar)

ve bu nedenle klasik

return
{ 
  foo: 1
}

JavaScript yorumlayıcısı bunu şu şekilde ele alacağından beklendiği gibi çalışmaz:

return;   // returning nothing
{
  foo: 1
}

Aşağıdakilerden hemen sonra hiçbir satır kesmesi olmamalıdır return:

return { 
  foo: 1
}

düzgün çalışması için. Ve herhangi bir ifadeden sonra ;kullanma kuralına uymanız durumunda kendiniz ekleyebilirsiniz ;:

return { 
  foo: 1
};

17

Noktalı virgül ekleme ve var deyimi ile ilgili olarak, var kullanırken virgül unutmayı unutmayın, ancak birden çok satırı kapsar. Birisi bunu dün kodumda buldu:

    var srcRecords = src.records
        srcIds = [];

Ancak, sonuç, srcIds bildirimi / atamasının global olmasıydı, çünkü önceki satırda var olan yerel bildirim artık otomatik yarı kolon yerleştirme nedeniyle bitmiş olarak kabul edildiğinden artık uygulanmadı.


4
Bu tür şey neden jsLint kullanıyorum
Zach Lysobey

1
JsHint / Lint hemen yanıt ile kod editörünüzde :)
dmi3y

5
@balupton Çizgiyi sonlandıracak virgül unutulduğunda, noktalı virgül otomatik olarak eklenir. Bir kuralın aksine, daha çok bir "gotcha" gibiydi.
Dexygen

1
Baluptonun doğru olduğunu düşünüyorum, yazmanız bir farktır: var srcRecords = src.records srcIds = [];bir satırda ve virgül unutun ya da "a & b döndürün" ve hiçbir şey unutmayın ... ama a'dan önceki satır sonu, dönüşten sonra otomatik noktalı virgül ekleyecektir, ASI kuralları tarafından tanımlanan ...
Sebastian

3
Her satıra var( let, const) yazmanın netliğinin, yazmak için gereken bir saniyeden daha ağır bastığını düşünüyorum.
squidbe

5

Bulduğum JavaScript'in Otomatik Noktalı virgül eklentisinin en bağlamsal açıklaması Tercüman Hazırlama hakkında bir kitaptan geliyor .

JavaScript'in “otomatik noktalı virgül ekleme” kuralı tuhaftır. Diğer dillerin çoğu yeni satırın anlamlı olduğunu ve çok satırlı ifadelerde yalnızca birkaçının göz ardı edilmesi gerektiğini varsayarsak, JS bunun tersini kabul eder. Bir ayrıştırma hatasıyla karşılaşmadıkça tüm yeni satırlarınıza anlamsız boşluk olarak davranır. Eğer öyleyse, geri gider ve dilbilgisel olarak geçerli bir şey elde etmek için önceki yeni satırı noktalı virgül haline getirmeye çalışır.

Kokuyu kodlayacağınız gibi tarif etmeye devam ediyor .

Bu tasarım notu, bunun nasıl çalıştığı hakkında tam bir ayrıntıya girersem, kötü bir fikir olan tüm çeşitli yollardan daha azına gidersem bir tasarım diatribe dönüşür. Bu bir karmaşa. JavaScript, dilin teorik olarak bunları seçmenize izin vermesine rağmen, birçok stil kılavuzunun her ifadeden sonra açık noktalı virgül gerektirdiğini bildiğim tek dildir.


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.