ECMAScript 6 tanıtıldı deyimi .let
"Yerel" bir değişken olarak tanımlandığını duydum, ancak yine de var
anahtar kelimeden nasıl farklı davrandığından emin değilim .
Farklılıklar nedir? Ne zaman let
kullanılmalıdır var
?
ECMAScript 6 tanıtıldı deyimi .let
"Yerel" bir değişken olarak tanımlandığını duydum, ancak yine de var
anahtar kelimeden nasıl farklı davrandığından emin değilim .
Farklılıklar nedir? Ne zaman let
kullanılmalıdır var
?
Yanıtlar:
Temel fark, kapsam belirleme kurallarıdır. var
Anahtar kelime tarafından bildirilen değişkenler , hemen işlev gövdesine (dolayısıyla işlev kapsamına), let
değişkenler ise hemen gösterilen kapalı bloğa { }
(dolayısıyla blok kapsamına) dahil edilir.
function run() {
var foo = "Foo";
let bar = "Bar";
console.log(foo, bar);
{
let baz = "Bazz";
console.log(baz);
}
console.log(baz); // ReferenceError
}
run();
let
Anahtar kelimenin dile tanıtılmasının nedeni işlev kapsamı kafa karıştırıcıydı ve JavaScript'teki ana hata kaynaklarından biriydi.
Bu örneğe başka bir yığın akışı sorusundan göz atın :
var funcs = [];
// let's create 3 functions
for (var i = 0; i < 3; i++) {
// and store them in funcs
funcs[i] = function() {
// each should log its value.
console.log("My value: " + i);
};
}
for (var j = 0; j < 3; j++) {
// and now let's run each one to see
funcs[j]();
}
My value: 3
funcs[j]();
anonim işlevler aynı değişkene bağlı olduğu için her seferinde konsola çıktı .
İnsanlar döngülerden doğru değeri yakalamak için hemen çağrılan işlevler oluşturmak zorundaydılar, ancak bu da kıllıydı.
var
Anahtar kelime ile bildirilen değişkenler kaldırılırken ( undefined
kod çalıştırılmadan önce başlatılır ), bu, bildirilmeden önce bile kapalı kapsamlarında erişilebilir oldukları anlamına gelir:
function run() {
console.log(foo); // undefined
var foo = "Foo";
console.log(foo); // Foo
}
run();
let
tanımları değerlendirilene kadar değişkenler başlatılmaz. Başlatmadan önce bunlara erişmek a ReferenceError
. Değişkenin, blok başlangıcından başlatma işlemine kadar "geçici ölü bölgede" olduğu söylenir.
function checkHoisting() {
console.log(foo); // ReferenceError
let foo = "Foo";
console.log(foo); // Foo
}
checkHoisting();
Üst düzeyde, let
aksine var
, genel nesne üzerinde bir özellik oluşturmaz:
var foo = "Foo"; // globally scoped
let bar = "Bar"; // globally scoped
console.log(window.foo); // Foo
console.log(window.bar); // undefined
Katı modda, SyntaxError'ı yükseltirken var
aynı değişkeni aynı kapsamda yeniden bildirmenize izin verir let
.
'use strict';
var foo = "foo1";
var foo = "foo2"; // No problem, 'foo' is replaced.
let bar = "bar1";
let bar = "bar2"; // SyntaxError: Identifier 'bar' has already been declared
let
blok ifadesi let (variable declaration) statement
standart değildir ve gelecekte kaldırılacaktır, bugzilla.mozilla.org/show_bug.cgi?id=1023609 .
let
kapaklarla ilgili sorunları önlemek için de kullanılabilir. Aşağıdaki örneklerde gösterildiği gibi eski bir referans tutmak yerine yeni bir değer bağlar.
for(var i=1; i<6; i++) {
$("#div" + i).click(function () { console.log(i); });
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>Clicking on each number will log to console:</p>
<div id="div1">1</div>
<div id="div2">2</div>
<div id="div3">3</div>
<div id="div4">4</div>
<div id="div5">5</div>
Yukarıdaki kod, klasik bir JavaScript kapatma sorunu olduğunu gösterir. i
Değişkene yapılan referans , gerçek değeri yerine tıklama işleyici kapatmasında saklanıyor i
.
Her bir tıklama işleyicisi aynı nesneye atıfta bulunacaktır, çünkü her bir tıklamada altı tane alacak şekilde 6 tutan tek bir sayaç nesnesi vardır.
Genel bir çözüm, bunu anonim bir işleve sarmak ve i
argüman olarak iletmektir. Bu konular da kullanarak artık önlenebilir let
yerine var
aşağıda kodda gösterildiği.
(Chrome ve Firefox 50'de test edilmiştir)
for(let i=1; i<6; i++) {
$("#div" + i).click(function () { console.log(i); });
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>Clicking on each number will log to console:</p>
<div id="div1">1</div>
<div id="div2">2</div>
<div id="div3">3</div>
<div id="div4">4</div>
<div id="div5">5</div>
let
, ancak tüm düğmeler için "6" uyarısı verir. Nasıl let
davranması gerektiğini söyleyen bir kaynağınız var mı?
let
gerçekten yararlı olacağını görebilirsiniz . Olay dinleyicilerini bir döngüde ayarlamak artık i
her yinelemede yerel olarak kapsam oluşturmak için hemen çağrılan bir işlev ifadesi gerektirmez .
let
ve var
?var
boyunca , fonksiyonun başlangıcından itibaren bilinir . (*)let
, sadece tanımlandığı blokta , tanımlandığı andan itibaren bilinir . (**)Farkı anlamak için aşağıdaki kodu göz önünde bulundurun:
// i IS NOT known here
// j IS NOT known here
// k IS known here, but undefined
// l IS NOT known here
function loop(arr) {
// i IS known here, but undefined
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
for( var i = 0; i < arr.length; i++ ) {
// i IS known here, and has a value
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
};
// i IS known here, and has a value
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
for( let j = 0; j < arr.length; j++ ) {
// i IS known here, and has a value
// j IS known here, and has a value
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
};
// i IS known here, and has a value
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
}
loop([1,2,3,4]);
for( var k = 0; k < arr.length; k++ ) {
// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS NOT known here
};
for( let l = 0; l < arr.length; l++ ) {
// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS known here, and has a value
};
loop([1,2,3,4]);
// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS NOT known here
Burada, değişkenimizin j
sadece döngü için ilkinde bilindiğini görüyoruz , ancak önce ve sonra değil. Ancak değişkenimiz i
tüm fonksiyonda bilinir.
Ayrıca, blok kapsamındaki değişkenlerin, kaldırılmadıkları için bildirilmeden önce bilinmediğini düşünün. Aynı blok kapsamındaki değişkeni aynı blok içinde yeniden bildirmenize de izin verilmez. Bu, blok kapsamındaki değişkenleri, genel veya işlevsel kapsamdaki değişkenlerden daha az hataya eğilimli hale getirir, bu da kaldırılır ve birden fazla bildirim olması durumunda hata üretmez.
let
Bugün kullanmak güvenli mi?Bazı insanlar ileride YALNIZCA izin ifadeleri kullanacağımızı ve var ifadelerinin kullanılmayacağını iddia edecektir. JavaScript gurusu Kyle Simpson neden böyle olmayacağına inandığı hakkında çok ayrıntılı bir makale yazdı .
Ancak bugün kesinlikle durum böyle değil. Aslında, let
ifadeyi kullanmanın güvenli olup olmadığını kendimize sormalıyız . Bu sorunun cevabı ortamınıza bağlıdır:
Sunucu tarafı JavaScript kodu ( Node.js ) yazıyorsanız, let
ifadeyi güvenle kullanabilirsiniz .
İstemci tarafı JavaScript kodu yazıyorsanız ve tarayıcı tabanlı bir transpiler ( Traceur veya babel-bağımsız gibi ) kullanıyorsanız, let
ifadeyi güvenle kullanabilirsiniz , ancak kodunuz performans açısından en uygun şey olabilir.
İstemci tarafı JavaScript kodu yazıyorsanız ve Düğüm tabanlı bir transpiler ( traceur shell betiği veya Babel gibi ) kullanıyorsanız, let
ifadeyi güvenle kullanabilirsiniz . Ve tarayıcınız sadece aktarılan kodu bileceğinden, performans dezavantajları sınırlı olmalıdır.
İstemci tarafı JavaScript kodu yazıyorsanız ve bir aktarıcı kullanmıyorsanız tarayıcı desteğini göz önünde bulundurmanız gerekir.
Hala hiç desteklemeyen bazı tarayıcılar var let
:
let
Bu yanıtı okurken hangi tarayıcıların ifadeyi desteklediğine dair güncel bir genel bakış için bu Can I Use
sayfaya bakın .
(*) Genel ve işlevsel kapsamdaki değişkenler, JavaScript değişkenleri kaldırıldığı için bildirilmeden önce başlatılabilir ve kullanılabilir . Bu, beyanların her zaman kapsamın en üstünde olduğu anlamına gelir.
(**) Blok kapsamındaki değişkenler kaldırılmamıştır
i
Fonksiyon bloğundaki her yerde biliniyor! undefined
Siz bir değer atayana kadar (kaldırma nedeniyle) olarak başlar ! ps: let
ayrıca (içerdiği bloğun üstüne) kaldırılır, ancak ReferenceError
ilk atamadan önce blokta referans verildiğinde bir zaman verir . (ps2: Ben noktalı virgül yanlısı bir adamım ama gerçekten bir bloktan sonra noktalı virgül kullanmanıza gerek yok). Bununla birlikte, destekle ilgili gerçeklik kontrolünü eklediğiniz için teşekkürler!
let
ve arasındaki kaldırma davranışındaki farkı açıklığa kavuşturacak birkaç iyileştirme yaptım var
.
let
ve const
alındı aslında onların ek işlevler gerektiğinde tek kullanım için tavsiye , 'daha çalışmalarında sonuç (salt const gibi) bu ekstra özellikler / zorlama kontrol çünkü '(ve kapsam ağacındaki ek kapsam düğümleri) için (mevcut) motor (lar) ın zorlanması / kontrol edilmesi / doğrulanması / ayarlanması.
İşte bazı örneklerle anahtar kelimenin açıklamasılet
.
let
çok benzer şekilde çalışırvar
. Temel fark, birvar
değişkenin kapsamının tüm çevreleme işlevi olmasıdır
Wikipedia'daki bu tablo , hangi tarayıcıların Javascript 1.7'yi desteklediğini gösterir.
Yalnızca Mozilla ve Chrome tarayıcılarının desteklediğini unutmayın. IE, Safari ve potansiyel olarak diğerleri değil.
Kabul edilen cevapta bir nokta eksik:
{
let a = 123;
};
console.log(a); // ReferenceError: a is not defined
for
döngü başlatıcısında gösterdi ve sınırlamalarının uygulama kapsamını önemli ölçüde daralttı let
. Upvoted.
let
let
Anahtar kelime kullanılarak bildirilen değişkenler blok kapsamlıdır, yani yalnızca bildirildikleri blokta kullanılabilirler .
En üst düzeyde, kullanılarak bildirilen değişkenler let
genel nesne üzerinde özellik oluşturmaz.
var globalVariable = 42;
let blockScopedVariable = 43;
console.log(globalVariable); // 42
console.log(blockScopedVariable); // 43
console.log(this.globalVariable); // 42
console.log(this.blockScopedVariable); // undefined
Bir işlevin içinde (ancak bir bloğun dışında), let
ile aynı kapsama sahiptir var
.
(() => {
var functionScopedVariable = 42;
let blockScopedVariable = 43;
console.log(functionScopedVariable); // 42
console.log(blockScopedVariable); // 43
})();
console.log(functionScopedVariable); // ReferenceError: functionScopedVariable is not defined
console.log(blockScopedVariable); // ReferenceError: blockScopedVariable is not defined
let
Bir bloğun içinde kullanıldığı bildirilen değişkenlere bu bloğun dışında erişilemez.
{
var globalVariable = 42;
let blockScopedVariable = 43;
console.log(globalVariable); // 42
console.log(blockScopedVariable); // 43
}
console.log(globalVariable); // 42
console.log(blockScopedVariable); // ReferenceError: blockScopedVariable is not defined
let
Döngülerde bildirilen değişkenlere yalnızca bu döngü içinde başvurulabilir.
for (var i = 0; i < 3; i++) {
var j = i * 2;
}
console.log(i); // 3
console.log(j); // 4
for (let k = 0; k < 3; k++) {
let l = k * 2;
}
console.log(typeof k); // undefined
console.log(typeof l); // undefined
// Trying to do console.log(k) or console.log(l) here would throw a ReferenceError.
Bir döngüde kullanmak let
yerine, var
her yinelemede yeni bir değişken elde edersiniz. Bu, bir döngü içinde güvenli bir şekilde bir kapak kullanabileceğiniz anlamına gelir.
// Logs 3 thrice, not what we meant.
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 0);
}
// Logs 0, 1 and 2, as expected.
for (let j = 0; j < 3; j++) {
setTimeout(() => console.log(j), 0);
}
Geçici ölü bölge nedeniyle, kullanılarak bildirilen değişkenlere, bildirilmeden let
önce erişilemez. Bunu yapmaya çalışmak hata verir.
console.log(noTDZ); // undefined
var noTDZ = 43;
console.log(hasTDZ); // ReferenceError: hasTDZ is not defined
let hasTDZ = 42;
Aynı değişkeni kullanarak birden çok kez bildiremezsiniz let
. Ayrıca, kullanılarak let
bildirilen başka bir değişkenle aynı tanımlayıcıyla bir değişkeni bildiremezsiniz var
.
var a;
var a; // Works fine.
let b;
let b; // SyntaxError: Identifier 'b' has already been declared
var c;
let c; // SyntaxError: Identifier 'c' has already been declared
const
const
oldukça benzer let
-Bu blok-kapsamlı ve sahip TGB. Ancak farklı olan iki şey vardır.
Kullanılarak bildirilen değişken const
yeniden atanamaz.
const a = 42;
a = 43; // TypeError: Assignment to constant variable.
Değerin değişmez olduğu anlamına gelmediğini unutmayın. Özellikleri hala değiştirilebilir.
const obj = {};
obj.a = 42;
console.log(obj.a); // 42
Değişmez bir nesneye sahip olmak istiyorsanız, kullanmalısınız Object.freeze()
.
Kullanarak bir değişken bildirirken her zaman bir değer belirtmelisiniz const
.
const a; // SyntaxError: Missing initializer in const declaration
İkisi arasındaki fark için bir örnek (chrome için yeni başlayan destek):
Gördüğünüz gibi, var j
değişken hala for döngüsü kapsamının (Blok Kapsamı) dışında bir değere sahiptir, ancak let i
değişken for döngüsü kapsamının dışında tanımlanmamıştır.
"use strict";
console.log("var:");
for (var j = 0; j < 2; j++) {
console.log(j);
}
console.log(j);
console.log("let:");
for (let i = 0; i < 2; i++) {
console.log(i);
}
console.log(i);
Bazı ince farklılıklar vardır - let
kapsam belirleme, az çok diğer dillerde değişken kapsam belirleme gibi davranır.
Örneğin, çevreleyen bloğu kapsamaktadır, Bildirilmeden önce mevcut değildirler, vb.
Ancak let
, daha yeni Javascript uygulamalarının sadece bir parçası olduğunu ve değişen derecelerde tarayıcı desteğine sahip olduğunu belirtmek gerekir .
let
dahil olduğunu ve büyük olasılıkla nihai spesifikasyonda olacağını belirtmek gerekir.
let
. Safari, IE ve Chome hepsi bilmiyor.
let
tanımlanmış bir değişken tarafından tanımlanan bir değişkeni kullanmak için dikkatli olun, dikkat edin, kaldırmayın let
. Bir varsa if
daha kod sadece birkaç satır daha deyimi, size o tanımlanır sonrasına kadar bu değişken kullanabilirsiniz olamayacağını unutabilir. BÜYÜK NOKTA !!!
let
kaldırırlar olacak bloğun üstüne değişkeni Ancak, değişken bildirimi sonuçlarında önce bloktaki değişkeni referans. ReferenceError (notumu: yerine iyi eski undefined
). değişken, bloğun başlangıcından bildirim işlenene kadar bir 'geçici ölü bölgede' olur. " Aynı şey "sadece bir temel blok olduğu için ifadeleri değiştir" için de geçerlidir. Kaynak: developer.mozilla.org/tr-TR/docs/Web/JavaScript/Reference/…
Temel fark ise kapsam iken, fark let içeride sadece mevcut olabilir kapsamı , döngü gibi o duyurulan var mesela döngü dışında erişilebilir. MDN'deki belgelerden (ayrıca MDN'den örnekler):
let , kapsamı ile sınırlı olan değişkenleri, kullanıldığı blok, ifade veya ifade ile bildirmenize izin verir. Bu, blok kapsamından bağımsız olarak bir değişkeni global olarak veya yerel olarak tüm bir işleve tanımlayan var anahtar sözcüğünden farklıdır .
Değişkenler tarafından ilan let kendi kapsamı gibi blok hangi tanımlandıkları gibi herhangi içerdiği alt bloklar halinde olan var. Bu şekilde, let çok gibi çalışır var . Ana fark, kapsamı olduğunu var değişken tüm parça işlevi:
function varTest() {
var x = 1;
if (true) {
var x = 2; // same variable!
console.log(x); // 2
}
console.log(x); // 2
}
function letTest() {
let x = 1;
if (true) {
let x = 2; // different variable
console.log(x); // 2
}
console.log(x); // 1
}`
Program ve fonksiyonları üst düzeyde, izin aksine, var , küresel nesne üzerinde bir özellik oluşturmaz. Örneğin:
var x = 'global';
let y = 'global';
console.log(this.x); // "global"
console.log(this.y); // undefined
Bir bloğun içinde kullanıldığında, değişkenin kapsamını bu bloğa sınırlar. Kapsamı bildirildiği işlevin içinde olan var arasındaki farka dikkat edin.
var a = 1;
var b = 2;
if (a === 1) {
var a = 11; // the scope is global
let b = 22; // the scope is inside the if-block
console.log(a); // 11
console.log(b); // 22
}
console.log(a); // 11
console.log(b); // 2
Ayrıca ECMA6 özelliğini de unutmayın, bu yüzden henüz tam olarak desteklenmemektedir, bu yüzden babel web sitesini ziyaret ederek daha fazla bilgi için her zaman Babel vb.
Değişken Kaldırma
let
olacak değil vinç onlar görünür bloğunun tüm kapsamıyla. Buna karşılık, var
aşağıdaki gibi kaldırırlar başladı.
{
console.log(cc); // undefined. Caused by hoisting
var cc = 23;
}
{
console.log(bb); // ReferenceError: bb is not defined
let bb = 23;
}
Aslında Per @Bergi, Hem var
ve let
kaldırılır .
Çöp toplama
Blok kapsamı, let
hafızayı geri kazanmak için kapaklar ve çöp toplama ile ilgilidir. Düşünmek,
function process(data) {
//...
}
var hugeData = { .. };
process(hugeData);
var btn = document.getElementById("mybutton");
btn.addEventListener( "click", function click(evt){
//....
});
click
İşleyici geri arama ihtiyacı yoktur hugeData
hiç değişkeni. Teorik olarak, çalışmalardan sonra process(..)
, büyük veri yapısı hugeData
çöp toplanabilir. Bununla birlikte, bazı JS motorunun hala bu büyük yapıyı korumak zorunda kalması mümkündür, çünkü click
işlev tüm kapsam üzerinde bir kapanışa sahiptir.
Ancak, blok kapsamı bu büyük veri yapısını toplanan çöp haline getirebilir.
function process(data) {
//...
}
{ // anything declared inside this block can be garbage collected
let hugeData = { .. };
process(hugeData);
}
var btn = document.getElementById("mybutton");
btn.addEventListener( "click", function click(evt){
//....
});
let
döngüler
let
döngüde, onu döngüdeki her yinelemeye yeniden bağlayabilir ve önceki döngü yinelemesinin sonundaki değeri yeniden atadığınızdan emin olun. Düşünmek,
// print '5' 5 times
for (var i = 0; i < 5; ++i) {
setTimeout(function () {
console.log(i);
}, 1000);
}
Ancak, yerine var
ilelet
// print 1, 2, 3, 4, 5. now
for (let i = 0; i < 5; ++i) {
setTimeout(function () {
console.log(i);
}, 1000);
}
Çünkü let
)), her bir yineleme Başlatıcı ekspresyon b bir için bu isimler ile yeni bir sözcük ortam yaratmak (previosly artış ifade) değerlendirmek için, daha fazla bilgi vardır burada .
İşte başkalarının yazdıklarına eklemek için bir örnek. adderFunctions
Her işlevin tek bir Sayı bağımsız değişkeni aldığı ve bağımsız değişken ile dizideki işlevin dizininin toplamını döndürdüğü bir dizi işlev yapmak istediğinizi varsayalım . Anahtar kelimeyi adderFunctions
kullanarak bir döngü oluşturmaya var
çalışmak, birinin naif bir şekilde beklediği gibi çalışmaz:
// An array of adder functions.
var adderFunctions = [];
for (var i = 0; i < 1000; i++) {
// We want the function at index i to add the index to its argument.
adderFunctions[i] = function(x) {
// What is i bound to here?
return x + i;
};
}
var add12 = adderFunctions[12];
// Uh oh. The function is bound to i in the outer scope, which is currently 1000.
console.log(add12(8) === 20); // => false
console.log(add12(8) === 1008); // => true
console.log(i); // => 1000
// It gets worse.
i = -8;
console.log(add12(8) === 0); // => true
Yukarıdaki işlem istenen işlev dizisini oluşturmaz çünkü i
kapsamı for
her işlevin oluşturulduğu bloğun yinelemesinin ötesine uzanır . Bunun yerine, döngünün sonunda, i
her bir işlevin kapanışı i
, içindeki her anonim işlev için döngünün sonunda (1000) değeri ifade eder adderFunctions
. İstediğimiz bu değil: şimdi bellekte tam olarak aynı davranışa sahip 1000 farklı fonksiyon dizimiz var. Ve daha sonra değerini güncellersek i
, mutasyon tümünü etkileyecektir adderFunctions
.
Ancak, şu let
anahtar kelimeyi kullanarak tekrar deneyebiliriz :
// Let's try this again.
// NOTE: We're using another ES6 keyword, const, for values that won't
// be reassigned. const and let have similar scoping behavior.
const adderFunctions = [];
for (let i = 0; i < 1000; i++) {
// NOTE: We're using the newer arrow function syntax this time, but
// using the "function(x) { ..." syntax from the previous example
// here would not change the behavior shown.
adderFunctions[i] = x => x + i;
}
const add12 = adderFunctions[12];
// Yay! The behavior is as expected.
console.log(add12(8) === 20); // => true
// i's scope doesn't extend outside the for loop.
console.log(i); // => ReferenceError: i is not defined
Bu kez, döngünün i
her yinelemesinde geri tepme olur for
. Artık her bir işlev i
, işlevin oluşturulması sırasında değerini korur ve adderFunctions
beklendiği gibi davranır.
Şimdi, iki davranışı karıştıran resim ve muhtemelen aynı komut dosyasında daha yeni let
ve const
daha eski olanlarla karıştırmanın neden önerilmediğini göreceksiniz var
. Bunu yapmak bazı şaşırtıcı kafa karıştırıcı kod olabilir.
const doubleAdderFunctions = [];
for (var i = 0; i < 1000; i++) {
const j = i;
doubleAdderFunctions[i] = x => x + i + j;
}
const add18 = doubleAdderFunctions[9];
const add24 = doubleAdderFunctions[12];
// It's not fun debugging situations like this, especially when the
// code is more complex than in this example.
console.log(add18(24) === 42); // => false
console.log(add24(18) === 42); // => false
console.log(add18(24) === add24(18)); // => false
console.log(add18(24) === 2018); // => false
console.log(add24(18) === 2018); // => false
console.log(add18(24) === 1033); // => true
console.log(add24(18) === 1030); // => true
Bunun olmasına izin verme. Bir linter kullanın.
NOT: Bu, döngülerdeki
var
/let
davranışı ve ayrıca anlaşılması kolay olan işlev kapanışlarıyla / davranışını göstermeyi amaçlayan bir öğretme örneğidir . Bu sayı eklemenin korkunç bir yolu olurdu. Ancak, anonim işlev kapanışlarında veri yakalamanın genel tekniğine, gerçek bağlamda diğer bağlamlarda rastlanabilir. YMMV.
let value = i;
. for
İfadesi bir sözcük bloğu oluşturur.
Fark, her biri ile bildirilen değişkenlerin kapsamındadır .
Uygulamada, kapsam farkının birkaç yararlı sonucu vardır:
let
değişkenler yalnızca en yakın çevreleme bloklarında ( { ... }
) görünür .let
değişkenler yalnızca değişken bildirildikten sonra ortaya çıkan kod satırlarında kullanılabilir ( kaldırılsa bile !).let
değişkenler bir sonraki var
veya tarafından yeniden bildirilemez let
.let
değişkenler global window
nesneye eklenmez .let
değişkenlerin kapaklarla kullanımı kolaydır ( yarış koşullarına neden olmazlar ).Dayattığı kısıtlamalar let
değişkenlerin görünürlüğünü azaltmak ve beklenmedik adı çarpışmalar erken bulunabilir ihtimalini artırır. Bu, değişkenlerin erişilebilirliği de dahil olmak üzere izlenmesini ve nedenini kolaylaştırır (kullanılmayan belleği geri kazanmaya yardımcı olur).
Sonuç olarak, let
büyük programlarda kullanıldığında veya bağımsız olarak geliştirilen çerçeveler yeni ve beklenmedik şekillerde birleştirildiğinde değişkenlerin sorun yaratma olasılığı daha düşüktür.
var
bir döngüde (# 5) bir kapatma kullanırken veya kodunuzda (# 4) harici olarak görülebilir global değişkenleri bildirirken tek bağlayıcı efekti istediğinizden eminseniz yine de yararlı olabilir. Transpiler alanından ve ana dile göç var
ederse, ihracat için kullanımı desteklenebilir export
.
1. En yakın çevreleme bloğunun dışında kullanım yok:
Bu kod bloğu bir referans hatası verir çünkü ikinci kullanımı x
, bildirildiği blok dışında gerçekleşir let
:
{
let x = 1;
}
console.log(`x is ${x}`); // ReferenceError during parsing: "x is not defined".
Aksine, aynı örnek var
çalışır.
2. Beyan etmeden önce faydasız:
Bu kod bloğu, kod ReferenceError
çalıştırılmadan önce a atar , çünkü x
bildirilmeden önce kullanılır:
{
x = x + 1; // ReferenceError during parsing: "x is not defined".
let x;
console.log(`x is ${x}`); // Never runs.
}
Aksine, aynı örnek var
istisna atmadan ayrıştırılır ve çalışır.
3.
Yeniden bildirim yok: Aşağıdaki kod, bildirilen bir değişkenin let
daha sonra yeniden bildirilemeyebileceğini gösterir :
let x = 1;
let x = 2; // SyntaxError: Identifier 'x' has already been declared
4. Bağlı olmayan globaller window
:
var button = "I cause accidents because my name is too common.";
let link = "Though my name is common, I am harder to access from other JS files.";
console.log(link); // OK
console.log(window.link); // undefined (GOOD!)
console.log(window.button); // OK
5. Kapaklar ile kolay kullanım:
Bildirilen değişkenler, var
döngülerin içindeki kapaklarla iyi çalışmaz. Değişkenin i
zaman içinde farklı noktalarda sahip olduğu değer dizisini çıktılayan basit bir döngü :
for (let i = 0; i < 5; i++) {
console.log(`i is ${i}`), 125/*ms*/);
}
Özellikle, bu çıktı:
i is 0
i is 1
i is 2
i is 3
i is 4
JavaScript'te değişkenleri genellikle oluşturulduklarından çok daha geç bir zamanda kullanırız. Bunu, çıktıyı bir kapakla geciktirerek gösterdiğimizde setTimeout
:
for (let i = 0; i < 5; i++) {
setTimeout(_ => console.log(`i is ${i}`), 125/*ms*/);
}
... yapıştığımız sürece çıktı değişmeden kalır let
. Aksine, biz var i
onun yerine kullansaydık :
for (var i = 0; i < 5; i++) {
setTimeout(_ => console.log(`i is ${i}`), 125/*ms*/);
}
... döngü beklenmedik şekilde beş kez "i 5" olur:
i is 5
i is 5
i is 5
i is 5
i is 5
var
yerine let
, kod şuna eşittir: var i = 0; while (i < 5) { doSomethingLater(); i++; }
i
kapanışın dışındadır ve doSomethingLater()
yürütülen zamana göre i
zaten 5 kat artırılmıştır, dolayısıyla çıktı i is 5
beş kat daha fazladır. Kullanarak let
, değişken i
kapanış içindedir, bu nedenle her eşzamansız çağrı, i
oluşturulmuş 'global' kullanmak yerine kendi kopyasını alır var
.
for
. Daha doğru bir dönüşüm, daha karmaşık olsa da, klasik for (var i = 0; i < 5; i++) { (function(j) { setTimeout(_ => console.log(
i $ {j} ' dır ve ), 125/*ms*/); })(i); }
bu da her bir değerini fonksiyonun i
adıyla kaydetmek için bir "fonksiyon aktivasyon kaydı" sunar j
.
Aşağıdaki iki işlev farkı gösterebilir:
function varTest() {
var x = 31;
if (true) {
var x = 71; // Same variable!
console.log(x); // 71
}
console.log(x); // 71
}
function letTest() {
let x = 31;
if (true) {
let x = 71; // Different variable
console.log(x); // 71
}
console.log(x); // 31
}
let
ilginç, çünkü böyle bir şey yapmamıza izin veriyor:
(() => {
var count = 0;
for (let i = 0; i < 2; ++i) {
for (let i = 0; i < 2; ++i) {
for (let i = 0; i < 2; ++i) {
console.log(count++);
}
}
}
})();
Bu da saymaya neden olur [0, 7].
Buna karşılık
(() => {
var count = 0;
for (var i = 0; i < 2; ++i) {
for (var i = 0; i < 2; ++i) {
for (var i = 0; i < 2; ++i) {
console.log(count++);
}
}
}
})();
Sadece [0, 1] sayılır.
Arasındaki temel fark var
ve let
bu değişkenler ile deklare olduğu var
edilmektedir işlevi kapsamlı . Fonksiyonlar ile beyan Oysa let
olan blok kapsamlı . Örneğin:
function testVar () {
if(true) {
var foo = 'foo';
}
console.log(foo);
}
testVar();
// logs 'foo'
function testLet () {
if(true) {
let bar = 'bar';
}
console.log(bar);
}
testLet();
// reference error
// bar is scoped to the block of the if statement
değişkenler var
:
İlk işlev testVar
bildirildiğinde foo değişkeni olarak adlandırıldığında var
, if
ifadenin dışında da erişilebilir . Bu değişken fonksiyon kapsamında her yerdefoo
kullanılabilir .testVar
değişkenler let
:
İkinci işleve testLet
bildirilen değişken çubuğu çağrıldığında let
, yalnızca if
deyim içinde erişilebilir . Değişkenler ile bildirilen için let
olan blok kapsamlı (blok yuvarlak parantezler arasında kodudur örneğin if{}
, for{}
, function{}
).
let
değişkenler kaldırılmaz:var
Ve let
ile arasındaki bir diğer fark , beyan edilen değişkenlerle let
kaldırılmaz . Bir örnek, bu davranışı göstermenin en iyi yoludur:
ile değişkenler let
yok hoisted olsun:
console.log(letVar);
let letVar = 10;
// referenceError, the variable doesn't get hoisted
ile değişkenler var
do olsun Çekilen:
console.log(varVar);
var varVar = 10;
// logs undefined, the variable gets hoisted
let
eklenmez window
:Genel let
kapsamda bildirilen bir değişken (işlevde olmayan koddur) genel window
nesneye özellik olarak eklenmez . Örneğin (bu kod global kapsamdadır):
var bar = 5;
let foo = 10;
console.log(bar); // logs 5
console.log(foo); // logs 10
console.log(window.bar);
// logs 5, variable added to window object
console.log(window.foo);
// logs undefined, variable not added to window object
Ne zaman
let
kullanılmalıdırvar
?
Kullanım let
üzerinde var
bunu basitçe daha spesifik kapsama aldığı çünkü her. Bu, çok sayıda değişkenle uğraşırken oluşabilecek potansiyel adlandırma çakışmalarını azaltır. var
bir global değişkenin window
nesnede açıkça olmasını istediğinizde kullanılabilir (bu gerçekten gerekliyse her zaman dikkatlice düşünün).
var
küresel kapsam (kaldırma kabiliyeti olan) değişkendir.
let
ve const
blok kapsamıdır.
test.js
{
let l = 'let';
const c = 'const';
var v = 'var';
v2 = 'var 2';
}
console.log(v, this.v);
console.log(v2, this.v2);
console.log(l); // ReferenceError: l is not defined
console.log(c); // ReferenceError: c is not defined
Kullanırken let
let
Anahtar kelime ne olursa olsun bloğun (genellikle kapsamına değişken bildiriminde verdiği { .. }
o içerdiği oluyor çifti). Başka bir deyişle, let
örtük olarak değişken beyanı için herhangi bloğun kapsamını hijacks.
let
window
küresel olarak erişilemediğinden , nesnede değişkenlere erişilemez.
function a(){
{ // this is the Max Scope for let variable
let x = 12;
}
console.log(x);
}
a(); // Uncaught ReferenceError: x is not defined
Kullanırken var
var
ve ES5'teki değişkenlerin fonksiyonlarda kapsamları vardır, bu da değişkenlerin fonksiyon içinde geçerli olduğu ve fonksiyonun dışında olmadığı anlamına gelir.
var
değişkenlere, genel olarak erişilemedikleri için window
nesnede erişilebilir.
function a(){ // this is the Max Scope for var variable
{
var x = 12;
}
console.log(x);
}
a(); // 12
Eğer daha fazlasını öğrenmek istiyorsanız, aşağıdaki okumaya devam edin
kapsamına en ünlü görüşme sorulardan biri de tam kullanımını yeterli olabilir let
ve var
aşağıdaki gibi;
Kullanırken let
for (let i = 0; i < 10 ; i++) {
setTimeout(
function a() {
console.log(i); //print 0 to 9, that is literally AWW!!!
},
100 * i);
}
Bunun nedeni let
, her döngü yinelemesi için değişkenin kapsamı ve kendi kopyasına sahip olmasıdır.
Kullanırken var
for (var i = 0; i < 10 ; i++) {
setTimeout(
function a() {
console.log(i); //print 10 times 10
},
100 * i);
}
Bunun nedeni var
, her döngü yinelemesi için değişkenin kapsamlandırılması ve kopyasının paylaşılmış olmasıdır.
Spesifikasyonları doğru let
okursam , o zaman şükürler olsun ki , sadece özel üyelere benzetmek için kullanılan kendini çağıran işlevlerden kaçınmak için kullanılabilir - kod okunabilirliğini azaltan, hata ayıklamayı zorlaştıran, gerçek kod koruması veya başka bir fayda sağlamayan popüler bir tasarım deseni - belki birinin tatmin edici olması dışında anlambilim arzusu, bu yüzden kullanmayı bırakın. / rant
var SomeConstructor;
{
let privateScope = {};
SomeConstructor = function SomeConstructor () {
this.someProperty = "foo";
privateScope.hiddenProperty = "bar";
}
SomeConstructor.prototype.showPublic = function () {
console.log(this.someProperty); // foo
}
SomeConstructor.prototype.showPrivate = function () {
console.log(privateScope.hiddenProperty); // bar
}
}
var myInstance = new SomeConstructor();
myInstance.showPublic();
myInstance.showPrivate();
console.log(privateScope.hiddenProperty); // error
Bkz. ' Özel arayüzleri taklit etme '
let
misiniz? (Sanırım “kendini çağırma işlevi” ile IIFE demek istiyorsun.)
hiddenProperty
koydunuz? hiddenProperty
"Sınıfınızdaki" tüm örnekler için yalnızca bir tane vardır .
for (let i = 0; i < 5; i++) {
// i accessible ✔️
}
// i not accessible ❌
for (var i = 0; i < 5; i++) {
// i accessible ✔️
}
// i accessible ✔️
⚡️ Oynamak için sandbox ↓
Bazı hackler let
:
1.
let statistics = [16, 170, 10];
let [age, height, grade] = statistics;
console.log(height)
2.
let x = 120,
y = 12;
[x, y] = [y, x];
console.log(`x: ${x} y: ${y}`);
3.
let node = {
type: "Identifier",
name: "foo"
};
let { type, name, value } = node;
console.log(type); // "Identifier"
console.log(name); // "foo"
console.log(value); // undefined
let node = {
type: "Identifier"
};
let { type: localType, name: localName = "bar" } = node;
console.log(localType); // "Identifier"
console.log(localName); // "bar"
let
:let jar = {
numberOfCookies: 10,
get cookies() {
return this.numberOfCookies;
},
set cookies(value) {
this.numberOfCookies = value;
}
};
console.log(jar.cookies)
jar.cookies = 7;
console.log(jar.cookies)
let { type, name, value } = node;
? 3 özellik türü / adı / değeri olan yeni bir nesne oluşturup bunları düğümdeki özellik değerleriyle başlatır mısınız?
var
.
let vs var. Her şey kapsamla ilgili .
var değişkenleri geneldir ve temelde her yerde erişilebilirken, değişkenler genel değildir ve yalnızca bir kapanış parantezi onları öldürene kadar var olur.
Aşağıdaki örneğime bakın ve lion (let) değişkeninin iki console.logs içinde nasıl farklı davrandığını not edin; 2nd console.log dosyasında kapsam dışı olur.
var cat = "cat";
let dog = "dog";
var animals = () => {
var giraffe = "giraffe";
let lion = "lion";
console.log(cat); //will print 'cat'.
console.log(dog); //will print 'dog', because dog was declared outside this function (like var cat).
console.log(giraffe); //will print 'giraffe'.
console.log(lion); //will print 'lion', as lion is within scope.
}
console.log(giraffe); //will print 'giraffe', as giraffe is a global variable (var).
console.log(lion); //will print UNDEFINED, as lion is a 'let' variable and is now out of scope.
ES6 var yerine alternatif olarak iki yeni anahtar kelime ( let ve const ) tanıttı .
Bir blok düzeyinde yavaşlamaya ihtiyacınız olduğunda var yerine let ve const ile gidebilirsiniz.
Aşağıdaki tablo var, let ve const arasındaki farkı özetler
let es6'nın bir parçası. Bu işlevler farkı kolay bir şekilde açıklayacaktır.
function varTest() {
var x = 1;
if (true) {
var x = 2; // same variable!
console.log(x); // 2
}
console.log(x); // 2
}
function letTest() {
let x = 1;
if (true) {
let x = 2; // different variable
console.log(x); // 2
}
console.log(x); // 1
}
Aşağıda 'let' ve 'var' öğelerinin kapsamda nasıl farklı oldukları gösterilmiştir:
let gfoo = 123;
if (true) {
let gfoo = 456;
}
console.log(gfoo); // 123
var hfoo = 123;
if (true) {
var hfoo = 456;
}
console.log(hfoo); // 456
gfoo
Tarafından tanımlanan let
başlangıçta olduğu küresel kapsam ve biz bildirirken gfoo
içeride tekrar if clause
onun kapsamı değişti ve yeni bir değer olduğunu kapsam içine değişkene atandığında o etkilemez küresel kapsamı.
Bununla birlikte hfoo
, tarafından tanımlanmış var
başlangıçta küresel kapsamdadır , ancak yine içinde ilan if clause
ettiğimizde, var olanı beyan etmek için tekrar kullanılmasına rağmen, küresel kapsam hfoo'yu göz önünde bulundurur. Ve değerini yeniden atadığımızda, küresel kapsam hfoo'nun da etkilendiğini görüyoruz. Bu birincil farktır.
Yukarıda da belirtildiği gibi:
Fark kapsamıdır.
var
En yakın için kapsamlı fonksiyon bloğu velet
odaklanan yakın parça blok bir fonksiyon blok daha küçük olabilir. Herhangi bir bloğun dışındaysa her ikisi de globaldir.
Örnek 1:
Her iki örneğimde de bir fonksiyonum var myfunc
. 10'a eşit myfunc
bir değişken içerir myvar
. İlk myvar
örneğimde 10 ( myvar==10
) olup olmadığını kontrol ediyorum . Eğer evet ise, ben acian anahtar kelimeyi myvar
kullanarak bir değişken (şimdi iki myvar değişkenim var) beyan var
ve yeni bir değer atar (20). Bir sonraki satırda değerini konsoluma yazdırıyorum. Koşullu bloktan sonra myvar
konsolumun değerini tekrar yazdırıyorum . Eğer çıkışında bakarsak myfunc
, myvar
değer 20'ye eşittir vardır.
Örnek 2:var
Koşullu blokta anahtar kelime
kullanmak yerine ikinci örneğimde anahtar kelime myvar
kullandığımı beyan ederim let
. Şimdi aradığımda myfunc
iki farklı çıkış elde ediyorum: myvar=20
ve myvar=10
.
Yani fark çok basit yani kapsamı.
Yürütme Bağlamı tüm bunlar için önemlidir, çünkü bu anahtar kelimeleri Yürütme Bağlam bağlamak istiyorum. Yürütme Bağlamının iki aşaması vardır: Bir Oluşturma Safhası ve Yürütme Safhası. Ayrıca, her Yürütme Bağlamında Değişken Ortam ve Dış Ortam (Lexical Environment) vardır.
Bir Yürütme Bağlamının Oluşturma Aşaması sırasında, var, let ve const değişkenleri bellekte, belirli Yürütme Bağlamının Değişken Ortamında tanımlanmamış bir değerle depolanır. Fark Yürütme Aşamasındadır. Bir değer atanmadan önce var ile tanımlanan bir değişkeni başvuru kullanırsanız, yalnızca tanımsız olur. Herhangi bir istisna yapılmayacaktır.
Ancak, bildirilene kadar let veya const ile bildirilen değişkene başvuramazsınız. Bildirilmeden önce kullanmaya çalışırsanız, Yürütme Bağlamının Yürütme Aşaması sırasında bir istisna ortaya çıkar. Şimdi, değişken Yürütme Bağlamının Oluşturma Aşamasının izniyle hala bellekte olacaktır, ancak Motor bunu kullanmanıza izin vermeyecektir:
function a(){
b;
let b;
}
a();
> Uncaught ReferenceError: b is not defined
Var ile tanımlanan bir değişkenle, Motor değişkeni geçerli Yürütme Bağlamının Değişken Ortamında bulamazsa, kapsam zincirini (Dış Ortam) yukarı çıkar ve değişken için Dış Ortamın Değişken Ortamını kontrol eder. Orada bulamazsa, Kapsam Zincirini aramaya devam eder. Let ve const için durum böyle değil.
Let'in ikinci özelliği blok kapsamını tanıtmasıdır. Bloklar kıvırcık parantezlerle tanımlanır. Örnekler arasında fonksiyon blokları, bloklar, bloklar, vb. Sayılabilir. Bir bloğun içine izin verilen bir değişken bildirdiğinizde, değişken sadece bloğun içinde kullanılabilir. Aslında, blok bir for döngüsü içinde her çalıştırıldığında, bellekte yeni bir değişken oluşturur.
ES6 ayrıca değişkenleri bildirmek için const anahtar sözcüğünü sunar. const ayrıca blok kapsamlıdır. Let ve const arasındaki fark, const değişkenlerinin bir başlatıcı kullanarak bildirilmesi gerektiğidir, yoksa bir hata oluşturur.
Son olarak, Yürütme Bağlamı söz konusu olduğunda, var ile tanımlanan değişkenler 'this' nesnesine eklenir. Genel Yürütme Bağlamında, bu tarayıcılardaki pencere nesnesi olacaktır. İzin ya da inşa için durum böyle değil.
Ben terimler ve örneklerin çoğu biraz ezici olduğunu düşünüyorum, ben fark ile şahsen vardı ana konu bir "Blok" ne olduğunu anlamak. Bir noktada fark ettim, bir blok IF
ifade dışında herhangi bir süslü parantez olacaktır . bir {
fonksiyonun veya halkanın açılış braketi yeni bir blok tanımlayacaktır, let
içinde tanımlanmış herhangi bir şey }
, aynı şeyin (fonksiyon veya döngü) kapanış braketinden sonra kullanılamayacaktır ; Bunu akılda tutarak, anlamak daha kolaydı:
let msg = "Hello World";
function doWork() { // msg will be available since it was defined above this opening bracket!
let friends = 0;
console.log(msg);
// with VAR though:
for (var iCount2 = 0; iCount2 < 5; iCount2++) {} // iCount2 will be available after this closing bracket!
console.log(iCount2);
for (let iCount1 = 0; iCount1 < 5; iCount1++) {} // iCount1 will not be available behind this closing bracket, it will return undefined
console.log(iCount1);
} // friends will no be available after this closing bracket!
doWork();
console.log(friends);
Şimdi ben kullanarak bir deyimler bloğuna değişkenler daha iyi kapsamı düşünüyorum let
:
function printnums()
{
// i is not accessible here
for(let i = 0; i <10; i+=)
{
console.log(i);
}
// i is not accessible here
// j is accessible here
for(var j = 0; j <10; j++)
{
console.log(j);
}
// j is accessible here
}
Bence insanlar burada izin kullanmaya başlayacaklar, böylece JavaScript'te diğer diller, Java, C # vb.
JavaScript'te kapsam belirleme konusunda net bir anlayışa sahip olmayanlar, hatayı daha önce yapmıştır.
Kaldırma kullanımı ile desteklenmez let
.
Bu yaklaşımla JavaScript'te mevcut hatalar kaldırılıyor.
Ayrıntılı olarak ES6'ya bakın : daha iyi anlamak için izin verin ve kurun .
Bu makale var, let ve const arasındaki farkı açıkça tanımlamaktadır.
const
tanımlayıcının yeniden atanmayacağının bir işaretidir.
let
, bir devredeki sayaç veya algoritmadaki değer değişimi gibi değişkenin yeniden atanabileceğinin bir işaretidir. Ayrıca, değişkenin yalnızca tanımlandığı blokta kullanılacağına işaret eder, bu da her zaman tüm işlevini içermez.
var
artık JavaScript'te bir değişken tanımladığınızda mevcut olan en zayıf sinyaldir. Değişken yeniden atanabilir veya atanmayabilir ve değişken tüm bir işlev için veya yalnızca bir blok veya döngü amacıyla kullanılabilir veya kullanılmayabilir.
https://medium.com/javascript-scene/javascript-es6-var-let-or-const-ba58b8dcde75#.esmkpbg9b
let
dahil edilmiştir ve büyük olasılıkla nihai spesifikasyonda olacaktır.