Javascript'teki değişken bildirim sözdizimleri arasındaki fark (genel değişkenler dahil)?


292

Değişken bildirme arasında fark var mı:

var a=0; //1

...bu yoldan:

a=0; //2

...veya:

window.a=0; //3

küresel kapsamda mı?


2
AFAIK var a = 0; başka bir js dosyasında bildirilen başka bir harici js dosyası üzerinden değişken erişirken IE'de çalışmaz
Aivan Monceller

Window.a'yı bilmiyorum ama küresel kapsamda diğer 2 yol aynı.
programcı

1
@AivanMonceller gerçekten mi? bağlantı Lütfen.
Raynos

@Raynos, kendi web sitemde deneyimliyorum. IE6 spesifik olmalıdır. Var enum harici bir js dosyasında görünmesini alamadım ve html dosyasında satır içi javascript olarak atıfta bulunuyorum
Aivan Monceller

@Ashwini Genel kapsamda, pencere global nesnedir (tarayıcılarda). var a = 1; console.log (a) ' console.log (win
leebriggs

Yanıtlar:


557

Evet, pratikte genellikle büyük olanlar olmasa da, birkaç fark vardır.

Dördüncü bir yol var ve ES2015 (ES6) itibariyle iki tane daha var. Sonunda dördüncü yolu ekledim, ancak ES2015 yollarını # 1'den sonra ekledim (nedenini göreceksiniz), bu yüzden:

var a = 0;     // 1
let a = 0;     // 1.1 (new with ES2015)
const a = 0;   // 1.2 (new with ES2015)
a = 0;         // 2
window.a = 0;  // 3
this.a = 0;    // 4

Bu ifadeler açıklandı

1. var a = 0;

Bu , tarayıcılarda olduğu gibi (veya genel bir kapsam aracılığıyla , katı olmayan kodda) eriştiğimiz global nesnenin bir özelliği olan global bir değişken oluşturur . Diğer bazı özelliklerin aksine, özellik üzerinden kaldırılamaz .windowthisdelete

Şartname açısından, bir oluşturur bağlayıcı tanımlayıcı üzerinde nesne Çevre Kayıt için küresel ortamda . Bu, onu global nesnenin bir özelliği yapar, çünkü global nesne, global ortamın nesnesi Ortam Kaydı için tanımlayıcı bağlarının tutulduğu yerdir. Bu nedenle özellik silinebilir değildir: Sadece basit bir özellik değil, tanımlayıcı bir bağlayıcıdır.

Bağlama (değişken) kodun ilk satırı çalışmadan önce tanımlanır (aşağıdaki "Ne zaman varolur" bölümüne bakın).

Not üzerinde oluşturulan mülkiyet IE8 üzerinde ve daha önce o windowdeğil enumerable (içinde görünmüyor for..inifadeleri). IE9, Chrome, Firefox ve Opera'da numaralandırılabilir.


# 1.1 let a = 0;

Bu , global nesnenin bir özelliği olmayan bir global değişken oluşturur . Bu ES2015'ten itibaren yeni bir şey.

Spesifikasyon terimleriyle, global kayıt için Ortam Kaydı nesnesi yerine bildirimsel Ortam Kaydı üzerinde bir tanımlayıcı bağlayıcı oluşturur . Küresel çevre bir bölünme Çevre Kayıt, küresel nesne (gider eski eşyaları hepsi için tek sahip tektir nesne yeni şeyler herkes için Çevre Record) ve diğeri ( , ve yarattığı fonksiyonlar ) yok küresel nesneye geçin.letconstclass

Olduğu bağlayıcı oluşturulan onu kapsayan blokta herhangi adım adım kodu (herhangi bir genel kod çalışmadan önce, bu durumda) çalıştırılmadan önce, ama değil erişilebilir adım-adım yürütme ulaşıncaya kadar herhangi bir şekilde letaçıklama. Yürütme letifadeye ulaştığında, değişken erişilebilir. (Aşağıdaki "Ne zaman letve constgerçekleşir" bölümüne bakın.)


# 1.2 const a = 0;

Genel nesnenin bir özelliği olmayan bir genel sabit oluşturur.

constTam gibidir letEğer bir başlatıcı (sağlamalıdır dışında = valuekısım) ve oluşturulduktan sonra size sabitinin değerini değiştiremez. Kapakların altında, tam olarak benzer letancak tanımlayıcı bağlaması üzerinde bir değerin değiştirilemeyeceğini söyleyen bir bayrak bulunur. Kullanmak constsizin için üç şey yapar:

  1. Sabit değere atamaya çalışırsanız, ayrıştırma zamanı hatası yapar.
  2. Diğer programcılar için değişmeyen doğasını belgeler.
  3. JavaScript motorunun değişmeyecek şekilde optimize edilmesini sağlar.

2. a = 0;

Bu, dolaylı olarak genel nesne üzerinde bir özellik oluşturur . Normal bir özellik olduğu için silebilirsiniz. Ben tavsiye ederim değil sonradan kodunuzu okuyan herkes için belirsiz olabilir, bunu yaparken. ES5'in katı modunu kullanırsanız, bunu yapmak (var olmayan bir değişkene atama) bir hatadır. Katı modu kullanmak için birkaç nedenden biri.

Ve ilginç bir şekilde, yine IE8 ve öncesinde, numaralandırılamayan özellik oluşturuldu ( for..inifadelerde görünmüyor ). Bu garip, özellikle aşağıda # 3 verildi.


3. window.a = 0;

Bu window, genel nesneyi (tarayıcılarda; tarayıcı olmayan bazı ortamların globalNodeJS gibi eşdeğer bir global değişkeni vardır) kullanan genel nesneyi kullanarak açıkça genel nesne üzerinde bir özellik oluşturur . Normal bir özellik olduğu için silebilirsiniz.

Bu özellik ise IE8 üzerinde, enumerable ve önceki sürümleri ve diğer her tarayıcıda denedim.


4. this.a = 0;

Tam olarak # 3 gibi, ancak global nesneyi global thisyerine referans olarak kullanıyoruz window. Bu katı modda çalışmaz, çünkü katı modda global kod, thisglobal nesneye bir referansa sahip değildir (bunun undefinedyerine değeri vardır ).


Mülkleri silme

"Silme" veya "kaldırma" ile ne demek istiyorum a? Tam olarak: deleteAnahtar kelimeyle özelliği (tamamen) kaldırma :

window.a = 0;
display("'a' in window? " + ('a' in window)); // displays "true"
delete window.a;
display("'a' in window? " + ('a' in window)); // displays "false"

deletebir özelliği bir nesneden tamamen kaldırır. Sen özellikler eklenmiş ile bunu yapamam windowaracılığıyla dolaylı olarak var, deleteya sessizce göz ardı ya da (JavaScript uygulanması ve katı modda ister bağlı olarak) bir istisna atar edilir.

Uyarı : IE8 tekrar (ve muhtemelen daha önce ve kırık "uyumluluk" modunda IE9-IE11): İzin windowvermeniz gerektiğinde bile nesnenin özelliklerini silmenize izin vermez . Daha da kötüsü, denediğinizde bir istisna atar ( bu denemeyi IE8 ve diğer tarayıcılarda deneyin ). Bu yüzden windownesneden silerken, savunmacı olmalısınız:

try {
    delete window.prop;
}
catch (e) {
    window.prop = undefined;
}

Bu özelliği silmeye çalışır ve bir istisna atılırsa bir sonraki en iyi şeyi yapar ve özelliği olarak ayarlar undefined.

Bu sadecewindow nesne için geçerlidir ve sadece (bildiğim kadarıyla) IE8 ve öncesi (veya kırık "uyumluluk" modunda IE9-IE11) için geçerlidir. Diğer tarayıcılar, windowyukarıdaki kurallara tabi olarak özellikleri silme konusunda iyidir .


Ne zaman varolur

İfade aracılığıyla tanımlanan değişkenler , yürütme bağlamındaki herhangi bir adım adım kod çalıştırılmadan varönce oluşturulur ve bu nedenle özellik , ifadeden çok önce bulunur .var

Bu kafa karıştırıcı olabilir, bu yüzden bir göz atalım:

display("foo in window? " + ('foo' in window)); // displays "true"
display("window.foo = " + window.foo);          // displays "undefined"
display("bar in window? " + ('bar' in window)); // displays "false"
display("window.bar = " + window.bar);          // displays "undefined"
var foo = "f";
bar = "b";
display("foo in window? " + ('foo' in window)); // displays "true"
display("window.foo = " + window.foo);          // displays "f"
display("bar in window? " + ('bar' in window)); // displays "true"
display("window.bar = " + window.bar);          // displays "b"

Canlı örnek:

Gördüğünüz gibi, sembol fooilk satırdan önce tanımlanır, ancak sembol bardeğildir. İfadenin var foo = "f";olduğu yerde, gerçekten iki şey vardır: ilk kod satırı çalıştırılmadan önce gerçekleşen sembolü tanımlamak; ve çizginin adım adım akışta olduğu yerde gerçekleşen bu sembole bir atama yapmak. Bu, " varkaldırma" olarak bilinir, çünkü var fooparça, kapsamın en üstüne taşınır ("kaldırılır"), ancak foo = "f"parça orijinal konumunda bırakılır. (Bkz. Kötüvar anemik küçük blogumda yanlış anlaşılmış .)


Ne zaman letve constolur

letve constfarklı varşekillerde bir çift. Sorusuna alakalı yolu bağlayıcı herhangi adım adım kod çalışmadan önce oluşturulan tanımlamak rağmen, o değil ki erişilebilir kadar letya constdeyim ulaşılır.

Yani bu çalışırken:

display(a);    // undefined
var a = 0;
display(a);    // 0

Bu bir hata verir:

display(a);    // ReferenceError: a is not defined
let a = 0;
display(a);

Soruyla gerçekten ilgili olmayan letve constfarklı olan diğer iki yol varşunlardır:

  1. varHer zaman (küresel kod boyunca veya gösterilip işlevinde fonksiyon kodu boyunca) tüm yürütme içeriği için geçerlidir, ancak letve constsadece içinde başvurmaları bloğunun göründükleri. Olduğunu, varfonksiyonunu (veya global) kapsamı vardır, ama letve constblok kapsamına sahip.

  2. Tekrarlayan var aaynı bağlamda zararsız olmakla birlikte, varsa let a(veya const a), başka sahip let aveya bir const aya da var abir yazım hatasıdır.

İşte bunu gösteren letve constbu blok içindeki herhangi bir kod çalışmadan önce hemen bloklarında yürürlüğe girecek, ancak letveya constifadesine kadar erişilemeyen bir örnek :

var a = 0;
console.log(a);
if (true)
{
  console.log(a); // ReferenceError: a is not defined
  let a = 1;
  console.log(a);
}

Bloğun dışından console.logerişmek yerine ikincisinin başarısız olduğunu unutmayın a.


Konu dışı: Genel nesneyi karıştırmaktan kaçının ( window)

windowNesne çok özelliklere sahip darmadağın olur. Mümkün olduğunda, karmaşa eklememenizi şiddetle öneririz. Bunun yerine, sembollerinizi küçük bir pakete sarın ve nesneye en fazla bir sembol verin window. (Sık sık nesneye herhangi bir sembol windowvermezim.) Sembollerinizi içermek için tüm kodlarınızı içeren bir işlev kullanabilirsiniz ve isterseniz bu işlev anonim olabilir:

(function() {
    var a = 0; // `a` is NOT a property of `window` now

    function foo() {
        alert(a);   // Alerts "0", because `foo` can access `a`
    }
})();

Bu örnekte, bir işlevi tanımlarız ve hemen çalıştırırız ( ()sonunda).

Bu şekilde kullanılan bir işleve genellikle kapsam belirleme işlevi denir . Kapsam belirleme işlevinde tanımlanan işlevler, kapsam belirleme işlevinde tanımlanan değişkenlere erişebilir, çünkü bunlar bu veriler üzerinde kapanır (bkz: Anemik küçük blogumda kapaklar karmaşık değildir ).


yapabildiğim window['a']=0o ben bir harita olarak pencereyi kullanıyorum temizlemek için? windowbazı tarayıcılar buna izin vermeyecek ve beni kullanmaya zorlayacak şekilde özel window.ami?
Jayen

# 3 ile ilgili muhtemelen açıklığa kavuşmaya değer bir not : window.a = 0;sadece tarayıcı ortamlarında ve sadece kurallarla çalışır. Adlı bir değişkene küresel nesne Bağlama windowES Spec değil ve süre böylece, örneğin, V8 veya node.js için, işe yaramaz this.a = 0;(küresel yürütme bağlamında çağrıldığında) Spec beri herhangi bir ortamda çalışacak gelmez belirtmek olması gerektiğini bir küresel nesne. Kodunuzu Konu dışı bölümünde olduğu gibi bir IIFE'ye sarıyorsanız , genel nesneye doğrudan başvuru almak veya thisadlandırılmış bir parametre olarak iletebilirsiniz . windowglobal
Sherlock_HJ

@Sherlock_HJ: "Tarayıcılara" ekledim; bu da cevabın başlarında, ama insanların buna atlaması ihtimaline karşı ekledim. O anda spec olduğunu ; yalnızca geçişte olsa da, bunu yapmayan bir tarayıcı bulamazsınız. Ek B'de olmadığına biraz şaşırdım .
TJ Crowder

@TJCrowder, Yani, ile bildirilen bir global değişken var a = 0;otomatik olarak global nesnenin bir özelliği haline gelir. var b = 0;Bir fonksiyon bildirimi içinde beyan edersem , temeldeki bazı nesnelerin de özelliği olur mu?
ezpresso

@ezpresso: Hayır ve evet. (Onlar bir nesnenin özelliklerini olurum EnvironmentRecord ait VariableEnvironment ait ExecutionContext göründükleri; ayrıntılar burada ve burada ), ancak doğrudan erişmek için hiçbir yolu yoktur bu programın kodundan nesnesi.
TJ Crowder

40

Basit tutmak:

a = 0

Yukarıdaki kod bir global kapsam değişkeni verir

var a = 0;

Bu kod, geçerli kapsamda ve altında kullanılacak bir değişken verecektir

window.a = 0;

Bu genellikle global değişkenle aynıdır.


Kişisel ifadeleri "Yukarıdaki kod küresel kapsam değişkeni verir" ve "bunun altında bu kod geçerli kapsamda kullanılacak bir değişken verecektir ve" birlikte alındığında, öncelikle hattı ve erişimini kullanamaz düşündürmektedir a altında geçerli kapsam. Yapabilirsin. Ayrıca, "global değişken" kullanımınız biraz kapalı - "global değişken" dediğiniz iki yer, söylemediğiniz yerden daha küresel değil.
TJ Crowder

global kendisi, geçerli kapsamdan bahsettiğim yer de dahil olmak üzere, değişkene her yerden erişebileceğiniz / okuyabileceğiniz / yazabileceğiniz anlamına gelir. Eğer window.a ve 'a' nın komut dosyasında global olmayacağını önerirseniz,% 100 yanlışsınız demektir.
Umair Jabbar

3
@Umair: "global kendisi, değişkene her yerden erişebileceğiniz / okuyabileceğiniz / yazabileceğiniz anlamına gelir" Doğru. Yine, ilk ve sonuncuyu ortadan daha "küresel" olarak adlandırıyor gibi görünüyorsunuz, elbette öyle değiller.
TJ Crowder

4
ortadaki fonksiyonun içinde kullanılır kabul edilir, ana kapsam altında kullanılırsa hepsi aynı olacaktır. bir fonksiyonun içinde var kullanmak benim varsayımımdı
Umair Jabbar

4
@Umair: "bir fonksiyonun içinde var kullanmak benim varsayımımdı" Ah, tamam. Ama soru bu değil. Soru açıkça "küresel kapsamda" diyor . Varsayımı (daha genel bir noktayı genişletmek ve açıklamak için yeterince adil olan) değiştirecekseniz, cevabınızda yaptığınız şeyin açık olması gerekir.
TJ Crowder

10
<title>Index.html</title>
<script>
    var varDeclaration = true;
    noVarDeclaration = true;
    window.hungOnWindow = true;
    document.hungOnDocument = true;
</script>
<script src="external.js"></script>

/* external.js */

console.info(varDeclaration == true); // could be .log, alert etc
// returns false in IE8

console.info(noVarDeclaration == true); // could be .log, alert etc
// returns false in IE8

console.info(window.hungOnWindow == true); // could be .log, alert etc
// returns true in IE8

console.info(document.hungOnDocument == true); // could be .log, alert etc
// returns ??? in IE8 (untested!)  *I personally find this more clugy than hanging off window obj

Varsayılan olarak tüm değişkenlerin askıda bırakıldığı global bir nesne var mı? örneğin: 'globals.noVar bildirimi'


Çok güzel bir keşif. window.*Beyannameyi kullanmak için kesin kılavuz . Bu bildirim, kodunuzun kopyalanmasına karşı en güvenli görünüme sahiptir ve ayrıca temizlenir.
Dan

7

TJ Crowder'ın mükemmel cevabına dayanarak : ( Konu dışı:window Karışıklıktan kaçının )

Bu onun fikrinin bir örneğidir:

Html

<!DOCTYPE html>
<html>
  <head>
    <script type="text/javascript" src="init.js"></script>
    <script type="text/javascript">
      MYLIBRARY.init(["firstValue", 2, "thirdValue"]);
    </script>
    <script src="script.js"></script>
  </head>

  <body>
    <h1>Hello !</h1>
  </body>    
</html>

init.js ( Bu yanıta göre )

var MYLIBRARY = MYLIBRARY || (function(){
    var _args = {}; // private

    return {
        init : function(Args) {
            _args = Args;
            // some other initialising
        },
        helloWorld : function(i) {
            return _args[i];
        }
    };
}());

script.js

// Here you can use the values defined in the html as if it were a global variable
var a = "Hello World " + MYLIBRARY.helloWorld(2);

alert(a);

İşte plnkr . Umarım yardımcı olur!


5

Küresel kapsamda anlamsal bir fark yoktur.

Ancak a=0kayıt dışı bir değişken için bir değer ayarladığınızdan gerçekten kaçınmalısınız .

Ayrıca global kapsamı düzenlemekten kaçınmak için kapaklar kullanın

(function() {
   // do stuff locally

   // Hoist something to global scope
   window.someGlobal = someLocal
}());

Mutlaka gerekli olduğunda daima kapakları kullanın ve daima küresel kapsamda kaldırın. Zaten iletişiminizin çoğu için eşzamansız olay işleme kullanıyor olmalısınız.

@AvianMoncellor'un belirttiği gibi bir IE hatası var var a = foosadece dosya kapsamı için bir global bildiriyor . Bu IE'nin kötü şöhretli kırık tercümanı ile ilgili bir sorundur. Bu hata tanıdık geliyor, bu yüzden muhtemelen doğrudur.

Öyleyse sadık kal window.globalName = someLocalpointer


2
"Küresel kapsamda anlamsal bir fark yoktur." Ancak pratik açıdan sadece küçük bir aşağı kaynar - Aslında çok büyük bir semantik fark var, mülkiyet tanımlanan alır hangi mekanizmalar tamamen farklıdır fiili (de yapamazsın o farkı deletebir var).
TJ Crowder

@TJ Crowder Bunu bilmiyordum. Değişken bildirimi değişken nesne özellikleri ayarlama olduğunu düşündüm. Bunların silinemeyeceğini bilmiyordum.
Raynos

Evet. Ayrıca kullanırsanız daha önce tanımlanırlar var. Bunlar sadece aynı pratik sonuca sahip tamamen farklı mekanizmalar. :-)
TJ Crowder

@TJ Crowder Kapsamın sonuna varatladığını söylemeyi unuttum .
Raynos
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.