JavaScript'teki değişkenlerin kapsamı nedir?


2013

Javascript'teki değişkenlerin kapsamı nedir? Bir fonksiyonun dışında içeride aynı kapsama sahipler mi? Yoksa önemi var mı? Ayrıca, değişkenler global olarak tanımlanırsa nerede saklanır?


4
İşte bu konuyu akılda tutmak için bir başka güzel bağlantı : " JavaScript kapsamını ve kapanışlarını açıklama ".
Full Stack Yazılım Mühendisi

9
İşte bunu çok güzel açıklayan bir makale. Javascript değişken kapsamı hakkında bilmeniz gereken her şey
Saurab Parakh

2
Daha önce bahsedilen Kyle Simpson e-kitabı Github'da okunabilir ve JavaScript Kapsamları ve Kapanışları hakkında bilmeniz gereken her şeyi anlatır. Burada bulabilirsiniz: github.com/getify/You-Dont-Know-JS/blob/master/… "JS bilmiyorsunuz" kitap serisinin bir parçası, bilmek isteyen herkes için harika JavaScript hakkında daha fazla bilgi.
3rik82

Yanıtlar:


2535

TLDR

JavaScript sözcüksel (statik olarak da adlandırılır) kapsamlandırma ve kapanışa sahiptir. Bu, kaynak koduna bakarak bir tanımlayıcının kapsamını anlatabileceğiniz anlamına gelir.

Dört kapsam:

  1. Global - her şey tarafından görülebilir
  2. İşlev - bir işlev içinde görünür (ve alt işlevleri ve blokları)
  3. Blok - bir blok içinde (ve alt bloklarında) görünür
  4. Modül - bir modül içinde görülebilir

Global ve modül kapsamındaki özel durumlar dışında, değişkenler var(fonksiyon kapsamı), let(blok kapsamı) ve const(blok kapsamı) kullanılarak bildirilir. Diğer tanımlayıcı bildirim biçimlerinin çoğu katı modda blok kapsamına sahiptir.

genel bakış

Kapsam, kod tabanının üzerinde bir tanımlayıcının geçerli olduğu bölgedir.

Sözcüksel ortam, tanımlayıcı adları ile bunlarla ilişkili değerler arasındaki eşlemedir.

Kapsam, sözcüksel ortamların bağlantılı bir yuvalamasından oluşur; yuvalamadaki her seviye, bir ata yürütme bağlamının sözcüksel ortamına karşılık gelir.

Bu bağlantılı sözcüksel ortamlar bir kapsam "zinciri" oluştururlar. Tanımlayıcı çözünürlüğü, bu zincir boyunca eşleşen bir tanımlayıcı arama sürecidir.

Tanımlayıcı çözünürlüğü yalnızca bir yönde gerçekleşir: dışa doğru. Bu şekilde, dış sözcüksel ortamlar iç sözcüksel ortamları "göremez".

JavaScript'te bir tanımlayıcının kapsamına karar vermede üç ilgili faktör vardır :

  1. Bir tanımlayıcı nasıl beyan edildi
  2. Bir tanımlayıcının bildirildiği yer
  3. İster katı modda ister katı modda olun

Tanımlayıcıların bildirilebilme yollarından bazıları:

  1. var, letveconst
  2. Fonksiyon parametreleri
  3. Yakalama bloğu parametresi
  4. İşlev bildirimleri
  5. Adlandırılmış işlev ifadeleri
  6. Genel nesne üzerinde dolaylı olarak tanımlanmış özellikler (ör. varKatı olmayan modda eksik )
  7. import ifadeleri
  8. eval

Konum tanımlayıcılarından bazıları bildirilebilir:

  1. Global bağlam
  2. İşlev gövdesi
  3. Sıradan blok
  4. Bir kontrol yapısının üstü (ör. Döngü, eğer, iken vb.)
  5. Kontrol yapısı gövdesi
  6. Modüller

Beyan Stilleri

var

Kullanılarak bildirilen tanımlayıcıların , doğrudan genel bağlamda bildirilmeleri dışında var işlev kapsamı vardır; bu durumda, genel nesneye özellikler olarak eklenir ve genel kapsamı vardır. evalFonksiyonlarda kullanımları için ayrı kurallar vardır .

izin ver ve yap

Doğrudan küresel bağlamda beyan edildikleri zaman dışında blok kapsamı kullanılarak letve const blok kapsamı olarak tanımlanmış tanımlayıcılar , bu durumda genel kapsamı vardır.

Not: let, constve var tüm askıya alır . Bu, mantıksal tanım konumlarının çevreleyen kapsamlarının (blok veya işlev) en üstünde olduğu anlamına gelir. Ancak değişkenler kullanıldığını beyan etti letve constdenetim kaynak kodundaki bildirim noktasını geçene kadar okunamaz veya atanamaz. Ara dönem geçici ölü bölge olarak bilinir.

function f() {
    function g() {
        console.log(x)
    }
    let x = 1
    g()
}
f() // 1 because x is hoisted even though declared with `let`!

İşlev parametre adları

İşlev parametre adları, işlev gövdesine dahil edilir. Bunun hafif bir karmaşıklığı olduğuna dikkat edin. Varsayılan bağımsız değişken olarak bildirilen işlevler, işlev gövdesini değil, parametre listesini kapatır .

İşlev bildirimleri

İşlev bildirimlerinin katı modda blok kapsamı ve katı olmayan modda fonksiyon kapsamı vardır. Not: katı olmayan mod, farklı tarayıcıların ilginç tarihsel uygulamalarına dayanan karmaşık bir acil kurallar kümesidir.

Adlandırılmış işlev ifadeleri

Adlandırılmış işlev ifadeleri kendilerine dahil edilir (örneğin özyineleme amacıyla).

Genel nesne üzerinde dolaylı olarak tanımlanmış özellikler

Katı olmayan modda, genel nesne kapsam zincirinin en üstünde yer aldığından, genel nesne üzerindeki örtülü olarak tanımlanan özellikler genel kapsama sahiptir. Katı modda bunlara izin verilmez.

eval

Gelen evaldizeleri, değişkenler kullanılarak bildirilen vareğer geçerli kapsamda yer veya edilecek evaldolaylı olarak kullanılır küresel nesne üzerinde özellikler olarak,.

Örnekler

Aşağıdaki isimlerin çünkü ReferenceError atacağım x, yve zfonksiyonun hiçbir anlamı dışında var f.

function f() {
    var x = 1
    let y = 1
    const z = 1
}
console.log(typeof x) // undefined (because var has function scope!)
console.log(typeof y) // undefined (because the body of the function is a block)
console.log(typeof z) // undefined (because the body of the function is a block)

Aşağıdaki için ReferenceError atacağım yve zancak için xgörünürlüğü nedeniyle, xbloğun ile sınırlı değildir. Kontrol yapılarının organları tanımlayan Bloklar gibi if, forve while, benzer şekilde hareket eder.

{
    var x = 1
    let y = 1
    const z = 1
}
console.log(x) // 1
console.log(typeof y) // undefined because `y` has block scope
console.log(typeof z) // undefined because `z` has block scope

Aşağıda, işlev kapsamı xolduğundan döngü dışında görünür var:

for(var x = 0; x < 5; ++x) {}
console.log(x) // 5 (note this is outside the loop!)

... bu davranış nedeniyle vardöngülerde bildirilen değişkenlerin kapatılması konusunda dikkatli olmanız gerekir . Burada xbildirilen değişkenin yalnızca bir örneği vardır ve bu, mantıksal olarak döngünün dışında yer alır.

Aşağıdakiler 5beş kez yazdırılır ve daha sonra döngü dışına 5altıncı kez yazdırılır console.log:

for(var x = 0; x < 5; ++x) {
    setTimeout(() => console.log(x)) // closes over the `x` which is logically positioned at the top of the enclosing scope, above the loop
}
console.log(x) // note: visible outside the loop

Aşağıdakiler yazdırılır undefinedçünkü xblok kapsamlıdır. Geri aramalar eşzamansız olarak tek tek çalıştırılır. Yeni davranış lether anonim işlev adında farklı bir değişkenin üzerinde kapalı olduğu değişkenler yardımıyla x(o yapmış olabilirler ki aksine var) ve tamsayılar böylece 0aracılığıyla 4yazdırılır .:

for(let x = 0; x < 5; ++x) {
    setTimeout(() => console.log(x)) // `let` declarations are re-declared on a per-iteration basis, so the closures capture different variables
}
console.log(typeof x) // undefined

Aşağıdakiler alamaz: ReferenceErrorçünkü görünürlüğü xblok tarafından kısıtlanmaz; ancak undefineddeğişken ( ififadeden dolayı ) başlatılmadığı için yazdırılacaktır .

if(false) {
    var x = 1
}
console.log(x) // here, `x` has been declared, but not initialised

forKullanarak bir döngünün üstünde bildirilen bir değişken let, döngünün gövdesine dahil edilir:

for(let x = 0; x < 10; ++x) {} 
console.log(typeof x) // undefined, because `x` is block-scoped

Aşağıdakiler atar, ReferenceErrorçünkü görünürlüğü xblok tarafından kısıtlanır:

if(false) {
    let x = 1
}
console.log(typeof x) // undefined, because `x` is block-scoped

Değişkenler kullanarak ilan var, letya consttüm modüllere kapsamına eklenir:

// module1.js

var x = 0
export function f() {}

//module2.js

import f from 'module1.js'

console.log(x) // throws ReferenceError

varGlobal bağlamda bildirilen değişkenler , global nesneye özellikler olarak eklendiğinden, aşağıdakiler genel nesne üzerinde bir özellik bildirir :

var x = 1
console.log(window.hasOwnProperty('x')) // true

letve constglobal bağlamda global nesneye özellikler eklemez, ancak yine de genel kapsamı vardır:

let x = 1
console.log(window.hasOwnProperty('x')) // false

İşlev parametrelerinin işlev gövdesinde bildirildiği kabul edilebilir:

function f(x) {}
console.log(typeof x) // undefined, because `x` is scoped to the function

Yakalama bloğu parametreleri catch-block gövdesine dahil edilir:

try {} catch(e) {}
console.log(typeof e) // undefined, because `e` is scoped to the catch block

Adlandırılmış işlev ifadeleri yalnızca ifadenin kendisine dahil edilir:

(function foo() { console.log(foo) })()
console.log(typeof foo) // undefined, because `foo` is scoped to its own expression

Katı olmayan modda, genel nesne üzerindeki dolaylı olarak tanımlanan özellikler genel olarak kapsamlandırılır. Katı modda bir hata alırsınız.

x = 1 // implicitly defined property on the global object (no "var"!)

console.log(x) // 1
console.log(window.hasOwnProperty('x')) // true

Katı olmayan modda işlev bildirimlerinin işlev kapsamı vardır. Katı modda blok kapsamı vardır.

'use strict'
{
    function foo() {}
}
console.log(typeof foo) // undefined, because `foo` is block-scoped

Kaputun altında nasıl çalışır

Kapsam, bir tanımlayıcının geçerli olduğu kodun sözlüksel bölgesi olarak tanımlanır.

JavaScript'te her işlev nesnesinin içinde oluşturulduğu yürütme bağlamının (yığın çerçevesi) sözcüksel ortamına[[Environment]] başvuru olan gizli bir başvurusu vardır .

Bir işlevi çağırdığınızda, gizli [[Call]]yöntem çağrılır. Bu yöntem yeni bir yürütme bağlamı oluşturur ve yeni yürütme bağlamı ile işlev nesnesinin sözcüksel ortamı arasında bir bağlantı kurar. Bunu [[Environment]], işlev nesnesindeki değeri yeni yürütme bağlamının sözcüksel ortamındaki bir dış başvuru alanına kopyalayarak yapar .

Yeni yürütme bağlamıyla işlev nesnesinin sözcüksel ortamı arasındaki bu bağlantıya kapatma adı verildiğini unutmayın .

Böylece, JavaScript'te kapsam, bir "zincir" içinde dış referanslarla birbirine bağlanan sözcüksel ortamlar aracılığıyla uygulanır. Sözcüksel ortamlar zincirine kapsam zinciri denir ve tanımlayıcı çözünürlüğü , zincirde eşleşen bir tanımlayıcı aranarak gerçekleşir .

Daha fazlasını öğrenin .


280
Kapsamlı olmaya bile yakın değil, belki de modern javascript'i bile OKUYMASI gereken Javascript kapsamı püf noktalarını bilmelidir.
Triptik

148
Yüksek puan alan bir cevap, neden olduğundan emin değilim. Bu, uygun bir açıklama yapmadan sadece bir grup örnektir, daha sonra prototip mirasını (yani özellik çözünürlüğü) kapsam zinciriyle (yani değişken çözünürlük) karıştırır. Kapsam ve özellik çözümünün kapsamlı (ve doğru) açıklaması comp.lang.javascript SSS notlarında bulunmaktadır .
RobG

109
@RobG Yüksek dereceli olduğu için küçük çaplı kataraktlara rağmen çok çeşitli programcılar için kullanışlı ve anlaşılabilir. Gönderdiğiniz bağlantı, bazı profesyoneller için yararlı olsa da, bugün Javascript yazan çoğu insan için anlaşılmaz. Cevabı düzenleyerek adlandırma sorunlarını gidermekten çekinmeyin.
Triptik

7
@ triptych — Sadece küçük şeyleri düzeltmek için cevapları düzenlerim, büyük değil. "Kapsam" ın "özellik" olarak değiştirilmesi hatayı düzeltir, ancak kalıtım ile kapsamı çok net bir ayrım yapmadan karıştırma sorunu çözmez.
RobG

24
Dış kapsamda bir değişken tanımlar ve sonra bir if ifadesinin aynı isimle işlevin içinde bir değişkeni tanımlaması, şubeye ulaşılmamış olsa bile yeniden tanımlanır. Bir örnek - jsfiddle.net/3CxVm
Chris S

233

Javascript, belirli bir işlevin kapsamını oluşturmak için kapsam zincirlerini kullanır. Genellikle bir global kapsam vardır ve tanımlanan her fonksiyonun kendi iç içe kapsamı vardır. Başka bir işlevde tanımlanan herhangi bir işlev, dış işleve bağlı yerel bir kapsama sahiptir. Her zaman kaynaktaki kapsamı tanımlayan konumdur.

Kapsam zincirindeki bir eleman temel olarak ana kapsamını gösteren bir Haritadır.

Bir değişkeni çözerken, javascript en iç kapsamda başlar ve dışa doğru arama yapar.


1
Kapsam zincirleri [bellek] Kapanışları için başka bir terimdir ... burada okuyanlar javascript öğrenmek / almak için.
Yeni İskenderiye

108

Küresel olarak beyan edilen değişkenlerin küresel bir kapsamı vardır. Bir işlev içinde bildirilen değişkenler o işleve dahil edilir ve aynı addaki global değişkenleri gölgelendirir.

(Eminim gerçek JavaScript programcılar diğer yanıtlar işaret etmek mümkün olacak birçok incelikler vardır ediyorum. Özellikle ben rastladım olarak bu sayfayı tam olarak ne hakkında thisherhangi bir zamanda aracı. Umarım bu daha tanıtıcı bağlantı Gerçi başlamak için yeterli olduğunu .)


7
Bu soruyu cevaplamaya bile başlamaktan korkuyorum. Gerçek bir Javascript Programcısı olarak cevabın ne kadar çabuk kontrolden çıkabileceğini biliyorum. Güzel makaleler.
Triptik

10
@Triptych: İşlerin kontrolden çıkmasıyla ilgili ne demek istediğini biliyorum, ama lütfen yine de bir cevap ekle. Ben gerçek deneyime sahip bir kişi tarafından yazılmış bir cevap olduğunu ... sadece aramaların bir çift yapmaktan yukarıda var bağlı iyi olması. Lütfen kesinlikle yanlış olan cevaplarımı düzeltin!
Jon Skeet

4
Bir şekilde Jon Skeet, Stack Overflow'daki en popüler cevabımdan sorumlu.
Triptik

75

Eski okul JavaScript

Geleneksel olarak, JavaScript gerçekten sadece iki tür kapsama sahiptir:

  1. Genel Kapsam : Değişkenler, uygulamanın başından itibaren uygulama boyunca bilinir (*)
  2. İşlevsel Kapsam : Değişkenler , işlevin başlangıcından itibaren bildirildikleri işlev içinde bilinir (*)

Farkı açıklayan başka birçok cevap olduğu için bunun üzerinde ayrıntılı bir şekilde durmayacağım.


Modern JavaScript

En son JavaScript gözlük şimdi de üçüncü bir kapsam sağlar:

  1. Blok Kapsamı : Tanımlayıcılar, içinde bildirildikleri kapsamın en üstünden "bilinir" , ancak bildirimlerinin sonuna kadar atanamaz veya kayıttan çıkartılamaz (okunamaz). Bu ara döneme "geçici ölü bölge" denir.

Blok kapsamı değişkenlerini nasıl oluştururum?

Geleneksel olarak, değişkenlerinizi şu şekilde yaratırsınız:

var myVariable = "Some text";

Blok kapsam değişkenleri şu şekilde oluşturulur:

let myVariable = "Some text";

Peki fonksiyonel kapsam ve blok kapsamı arasındaki fark nedir?

Fonksiyonel kapsam ve blok kapsamı arasındaki 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 jsadece döngü için ilkinde bilindiğini görüyoruz , ancak önce ve sonra değil. Ancak değişkenimiz itü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.


Bugün blok kapsamı değişkenlerini kullanmak güvenli mi?

Bugün kullanmanın güvenli olup olmadığı ortamınıza bağlıdır:

  • Sunucu tarafı JavaScript kodu ( Node.js ) yazıyorsanız, letifadeyi 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, letifadeyi 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, letifadeyi 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.

    Bunlar hiç desteklemeyen bazı tarayıcılardır let:

    • Internet Explorer 10 ve altı
    • Firefox 43 ve altı
    • Safari 9 ve altı
    • Android tarayıcı 4 ve altı
    • Opera 27 ve altı
    • Chome 40 ve altı
    • Opera Mini & Blackberry Browser'ın HERHANGİ BİR sürümü

resim açıklamasını buraya girin


Tarayıcı desteğini takip etme

letBu yanıtı okurken hangi tarayıcıların ifadeyi desteklediğine dair güncel bir genel bakış için bu Can I Usesayfaya 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.


2
"BİLİLMİYOR" yanıltıcıdır, çünkü değişken kaldırma nedeniyle orada bildirilmiştir.
Oriol

Yukarıdaki örnek yanıltıcıdır, 'i' ve 'j' değişkenleri blok dışında bilinmemektedir. 'Let' değişkenlerinin kapsamı yalnızca bloğun dışında olmayan belirli bir blokta bulunur. Diğer avantajları da olsun, değişkeni tekrar açıklayamazsınız ve söz konusu sözcük kapsamını korur.
Zakir

1
Bu yardımcı oldu, teşekkürler! "Modern JavaScript" ve "Old school JavaScript" ile kastettiğiniz hakkında spesifik olmanın daha yararlı olacağını düşünüyorum; Bunların sırasıyla ECMAScript 6 / ES6 / ECMAScript 2015 ve önceki sürümlerine karşılık geldiğini düşünüyorum?
Jon Schneider

1
@JonSchneider: Doğru! "Eski okul JavaScript'i" dediğimde, ECMAScript 5 ve "modern JavaScript" den bahsettiğim yerde ECMAScript 6 (ECMAScript 2015 olarak da bilinir) hakkında konuşuyorum. Bununla birlikte, burada ayrıntılara girmenin gerçekten önemli olduğunu düşünmüyordum, çünkü çoğu insan (1) blok kapsamı ve fonksiyonel kapsam arasındaki farkın ne olduğunu, (2) tarayıcıların blok kapsamını desteklediği ve (3) üzerinde çalıştıkları proje için blok kapsamını kullanmak güvenli olup olmadığı. Bu yüzden cevabımı bu sorunları ele almaya odakladım.
John Slegers

1
@JonSchneider: (devam) Yine de, son birkaç yıl içinde JavaScript'e hangi özelliklerin eklendiği hakkında daha fazla bilgi edinmek isteyenler için ES6 / ES2015'teki bir Smashing Magazine makalesine bir bağlantı ekledim ... "modern JavaScript" ile ne demek istediğimi merak ediyor olabilirsiniz.
John Slegers

39

İşte bir örnek:

<script>

var globalVariable = 7; //==window.globalVariable

function aGlobal( param ) { //==window.aGlobal(); 
                            //param is only accessible in this function
  var scopedToFunction = {
    //can't be accessed outside of this function

    nested : 3 //accessible by: scopedToFunction.nested
  };

  anotherGlobal = {
    //global because there's no `var`
  }; 

}

</script>

Kapakları ve bunları özel üyeler yapmak için nasıl kullanacağınızı araştırmak isteyeceksiniz .



26

"Javascript 1.7" de (Mozilla'nın Javascript'e eklenmesi) blok-kapsam değişkenlerini şu letifadeyle bildirebilir :

 var a = 4;
 let (a = 3) {
   alert(a); // 3
 }
 alert(a);   // 4

2
Evet, ama kullanımı güvenli mi? Kodum WebKit'te çalışacaksa gerçekçi bir şekilde bu uygulamayı seçer miyim?
IgorGanapolsky

10
@Python: Hayır, WebKit desteklemiyor let.
kennytm

Bunun için tek geçerli kullanım, tüm müşterilerin bir şirket içi sistem gibi bir Mozilla tarayıcısı kullanacağını bilseydiniz olurdu.
GazB

Veya XUL çerçevesini kullanarak programlama yapıyorsanız, Mozilla'nın css, xml ve javascript kullanarak oluşturduğunuz arayüz çerçevesi.
Gerard ONeill

1
@GazB bile bu korkunç bir fikir! Yani bugün müşterilerinizin Mozilla kullandığını biliyorsunuz, o zaman şimdi başka bir şey kullandıklarını belirten yeni bir not geliyor. IE ödeme sistemimizin berbat nedeni ... IE8 kullanmamalı ve asla IE9 veya IE10 veya Firefox veya Chrome kullanmamalısınız çünkü düz çalışmaz ...
buzzsawddog

25

Brendan Eich tarafından orijinal olarak tasarlandığında JavaScript'te kapsam oluşturma fikri HyperCard kodlama dili HyperTalk'tan geldi .

Bu dilde, ekranlar bir dizin kartı yığınına benzer şekilde yapıldı. Arka plan olarak adlandırılan bir ana kart vardı. Şeffaftı ve alt kart olarak görülebilir. Bu ana karttaki herhangi bir içerik, üzerine yerleştirilmiş kartlarla paylaşıldı. En üste yerleştirilen her kartın, önceki karttan önce gelen, ancak istenirse yine de önceki kartlara erişimi olan kendi içeriği vardı.

Tam olarak JavaScript kapsam belirleme sistemi bu şekilde tasarlanmıştır. Sadece farklı isimleri var. JavaScript'teki kartlar Yürütme Bağlamları ECMA olarak bilinir . Bu bağlamların her biri üç ana bölüm içerir. Değişken bir ortam, sözcüksel bir ortam ve bu bağlanma. Kart referansına geri dönersek, sözlü ortam, yığının altında bulunan önceki kartların tüm içeriğini içerir. Geçerli bağlam yığının en üstünde yer alır ve orada bildirilen herhangi bir içerik değişken ortamda depolanır. Çarpışmaların adlandırılması durumunda değişken ortam öncelikli olacaktır.

Bu bağlanma, içeren nesneyi gösterecektir. Bazen kapsamlar veya yürütme bağlamları, içerilen nesnenin olabileceği bildirilen bir işlev windowveya bir yapıcı işlevi gibi, içerilen nesne değişmeden değişir .

Bu yürütme bağlamları, denetimin aktarıldığı her seferde oluşturulur. Kod yürütülmeye başladığında kontrol aktarılır ve bu öncelikle işlev yürütmesinden yapılır.

Yani teknik açıklama budur. Uygulamada, JavaScript'te bunu hatırlamak önemlidir.

  • Kapsamlar teknik olarak "Yürütme Bağlamları" dır
  • Bağlamlar, değişkenlerin depolandığı ortam yığınını oluşturur
  • Yığının üst kısmı önceliklidir (alt kısmı genel bağlamdır)
  • Her işlev bir yürütme bağlamı oluşturur (ancak bu bağlama her zaman yeni değildir)

Bunu bu sayfadaki önceki örneklerden birine (5. "Kapatma") uygulayarak yürütme bağlamları yığınını takip etmek mümkündür. Bu örnekte, yığınta üç bağlam vardır. Dış bağlam, var altı tarafından çağrılan hemen çağrılan fonksiyondaki bağlam ve var altı'nın hemen çağrılan fonksiyonunun içindeki döndürülen fonksiyondaki bağlam ile tanımlanırlar.

i ) Dış bağlam. A = 1 değişken ortamına sahiptir
ii ) IIFE bağlamı, a = 1 lexik ortamına sahiptir, ancak yığında öncelikli olan a = 6 değişken ortamına sahiptir
iii ) Döndürülen fonksiyon bağlamı a = 6 ortamına sahiptir ve çağrıda uyarıda belirtilen değerdir.

resim açıklamasını buraya girin


17

1) Küresel bir kapsam, bir fonksiyon kapsamı ve with ve catch kapsamları vardır. Değişkenler için genel olarak 'blok' seviye kapsamı yoktur - with ve catch deyimleri bloklarına isim ekler.

2) Kapsamlar, global kapsamın sonuna kadar işlevler tarafından iç içe yerleştirilir.

3) Özellikler, prototip zinciri üzerinden çözülür. With ifadesi, nesne özelliği adlarını with bloğu tarafından tanımlanan sözcük kapsamına getirir.

DÜZENLEME: ECMAAScript 6 (Harmony) izin desteklemek için spesifikasyon olduğunu ve krom 'uyum' bayrağı izin verir biliyorum, bu yüzden belki de destekliyor ..

Izin vermek blok düzeyinde kapsam belirleme için bir destek, ama bunu yapmak için anahtar kelime kullanmak zorunda.

EDIT: Benjamin'in yorumlarda ve catch ifadeleri işaret dayalı, yazı düzenledim ve daha ekledim. Hem ile ve yakalamak ifadeleri kendi bloklar halinde değişkenleri tanıtmak ve bu ise bir blok kapsamı. Bu değişkenler, kendilerine iletilen nesnelerin özelliklerine takma olarak yerleştirilir.

 //chrome (v8)

 var a = { 'test1':'test1val' }
 test1   // error not defined
 with (a) { var test1 = 'replaced' }
 test1   // undefined
 a       // a.test1 = 'replaced'

EDIT: Açıklayıcı örnek:

test1, tümce bloğuna dahil edilir, ancak a.test1'e takma olarak adlandırılır. 'Var test1', üstteki sözcüksel bağlamda (işlev veya global) yeni bir değişken1 oluşturur;

Olmadı! 'With' komutunu kullanırken dikkatli olun - değişkenin işlevde zaten tanımlanmış olması durumunda var'ın bir noop olması gibi, nesneden içe aktarılan isimler açısından da bir nooptur! Zaten tanımlanmış olan isme biraz kafa vurmak bunu daha güvenli hale getirecektir. Ben şahsen bu yüzden asla kullanmayacağım.


Burada bazı hatalarınız var, çünkü bir JavaScript'in blok kapsam belirleme biçimleri var.
Benjamin Gruenbaum

Kulaklarım (gözlerim) açık, Benjamin - Yukarıdaki ifadelerim, Javascript kapsam belirleme yöntemini nasıl tedavi ettiğimi, ancak spesifikasyonu okumaya dayanmıyorlar. Ve umarım with deyiminden (nesne kapsam belirleme biçimidir) veya Mozilla'nın özel 'let' sözdiziminden bahsetmiyorsunuzdur.
Gerard ONeill

Eh, withdeyim olan blok kapsam belirleme şeklidir ama catchcümleleri çok daha sık görülen (İşin eğlenceli yanı, v8 uygular olan catchbir ile with) - JavaScript kendisi (Yani, fonksiyon, küresel, deneme / yakalama hemen hemen blok Kapsam belirlemenin tek formlarını var Bununla birlikte, ana bilgisayar ortamları farklı kapsamlandırma kavramlarına sahiptir - örneğin tarayıcıdaki satır içi olaylar ve NodeJS'nin vm modülü.
Benjamin Gruenbaum

Benjamin - görebildiğim kadarıyla, hem mevcut hem de catch ile nesneyi sadece geçerli kapsama (ve böylece özelliklere) tanıtın, ancak daha sonra ilgili blok bittikten sonra değişkenler sıfırlanır. Ancak, örneğin, yakalamaya eklenen yeni bir değişken, kapalı fonksiyon / yöntemin kapsamına sahip olacaktır.
Gerard ONeill

2
Bu tam olarak blok
kapsamasının anlamıdır

9

JavaScript'te yeni olan birçok kişinin, dilde kalıtımın varsayılan olarak kullanılabildiğini ve işlev kapsamının şimdiye kadar tek kapsam olduğunu anlamada sorun yaşadığını gördüm. Geçen yılın sonunda yazdığım bir güzelliğe JSPretty adlı bir uzantı sağladım. Özellik renkleri koddaki kapsamı işlev görür ve her zaman bir rengi o kapsamda bildirilen tüm değişkenlerle ilişkilendirir. Bir kapsamdan bir renge sahip bir değişken farklı bir kapsamda kullanıldığında kapatma görsel olarak gösterilir.

Özelliği şurada deneyin:

Bir demoya bakın:

Kodu şurada görüntüleyin:

Şu anda bu özellik 16 iç içe işlev derinliği için destek sunuyor, ancak şu anda global değişkenleri renklendirmiyor.


1
Firefox 26 ile benim için çalışmıyor. Kodu yapıştırıyorum veya bir dosya yüklüyorum, çalıştır'ı tıklayın ve hiçbir şey olmuyor.
mplwork

Kapsam ve kalıtım iki farklı şeydir.
Ben Aston

9

JavaScript'in yalnızca iki tür kapsamı vardır:

  1. Global Scope : Global, bir pencere seviyesi kapsamından başka bir şey değildir.
  2. İşlevsel Kapsam : varAnahtar sözcük içeren bir işlev içinde bildirilen değişkenin işlevsel kapsamı vardır.

Bir işlev çağrıldığında, bir değişken kapsam nesnesi oluşturulur (ve kapsam zincirine dahil edilir), bunu JavaScript'teki değişkenler izler.

        a = "global";
         function outer(){ 
              b = "local";
              console.log(a+b); //"globallocal"
         }
outer();

Kapsam zinciri ->

  1. Pencere seviyesi - ave outerfonksiyon kapsam zincirinde en üst seviyededir.
  2. dış işlev, içinde variable scope objectdeğişken bbulunan yeni (ve kapsam zincirine dahil) olarak adlandırıldığında.

Şimdi bir değişken agerektiğinde ilk önce en yakın değişken kapsamını arar ve eğer değişken orada değilse, değişken kapsam zincirinin bir sonraki nesnesine geçer. Bu durumda pencere seviyesi.


1
Bunun neden kabul edilen cevap olmadığından emin değilim. Aslında sadece işlevsel kapsam var (ECMA6'dan önce "yerel kapsam" yoktu) ve küresel bağlamalar var
texasbruce

9

Diğer yanıtlara eklemek için kapsam, bildirilen tüm tanımlayıcıların (değişkenler) bir arama listesidir ve bunların şu anda kod yürütme için nasıl erişilebilir olduğuna ilişkin katı bir kurallar dizisi uygular. Bu arama, bir LHS (sol taraf) referansı olan değişkene atama veya bir RHS (sağ taraf) referansı olan değerinin alınması amacıyla olabilir. Bu aramalar, JavaScript motorunun kodu derlerken ve yürütürken dahili olarak yaptığı şeydir.

Bu açıdan bakıldığında, bir resmin Kyle Simpson'ın Scopes and Closures e-kitabında bulduğumda yardımcı olacağını düşünüyorum:

görüntü

E-kitabından alıntı:

Bina, programımızın iç içe kapsam kural kümesini temsil eder. Binanın birinci katı, nerede olursanız olun şu anda yürütmekte olduğunuz kapsamı temsil eder. Binanın en üst seviyesi küresel kapsamdır. Mevcut katınıza bakarak LHS ve RHS referanslarını çözersiniz ve bulamazsanız asansörü bir sonraki kata götürür, oraya bakar, sonra bir sonrakine vb. En üst kata (global kapsam) ulaştığınızda, aradığınızı bulursunuz veya bulmazsınız. Ama ne olursa olsun durmalısın.

Bahsetmeye değer bir nokta, "İlk aramayı bulduktan sonra Kapsam araması durur".

Bu "kapsam düzeyleri" fikri, iç içe geçmiş bir işleve bakılıyorsa "bu" nun neden yeni oluşturulmuş bir kapsamla değiştirilebileceğini açıklar. İşte tüm bu ayrıntılara giren bir bağlantı, Javascript kapsamı hakkında bilmek istediğiniz her şey


8

kodu çalıştırın. umarım bu kapsam belirleme hakkında bir fikir verir

Name = 'global data';
document.Name = 'current document data';
(function(window,document){
var Name = 'local data';
var myObj = {
    Name: 'object data',
    f: function(){
        alert(this.Name);
    }
};

myObj.newFun = function(){
    alert(this.Name);
}

function testFun(){
    alert("Window Scope : " + window.Name + 
          "\nLocal Scope : " + Name + 
          "\nObject Scope : " + this.Name + 
          "\nCurrent document Scope : " + document.Name
         );
}


testFun.call(myObj);
})(window,document);

8

Global Kapsam:

Küresel değişkenler aynen küresel yıldızlar gibidir (Jackie Chan, Nelson Mandela). Bunlara, uygulamanızın herhangi bir bölümünden erişebilir (değeri alabilir veya ayarlayabilirsiniz). Küresel işlevler, küresel olaylar gibidir (Yeni Yıl, Noel). Bunları uygulamanızın herhangi bir bölümünden yürütebilir (arayabilirsiniz).

//global variable
var a = 2;

//global function
function b(){
   console.log(a);  //access global variable
}

Yerel Kapsam:

ABD'deyseniz, ünlü olan Kim Kardashian'ı tanıyabilirsiniz (bir şekilde tabloidleri yapmayı başarıyor). Fakat ABD dışındaki insanlar onu tanımayacaklar. Bölgesine bağlı yerel bir yıldızdır.

Yerel değişkenler yerel yıldızlar gibidir. Bunlara yalnızca kapsam içinden erişebilir (değeri alabilir veya ayarlayabilirsiniz). Yerel bir işlev yerel etkinlikler gibidir - bu kapsamda yalnızca yürütme (kutlama) yapabilirsiniz. Bunlara kapsamın dışından erişmek istiyorsanız, bir referans hatası alırsınız

function b(){
   var d = 21; //local variable
   console.log(d);

   function dog(){  console.log(a); }
     dog(); //execute local function
}

 console.log(d); //ReferenceError: dddddd is not defined    

Kapsamın derinlemesine anlaşılması için bu makaleye göz atın.


6

ALMOST yalnızca iki tür JavaScript kapsamı içerir:

  • her bir varyantın kapsamı, en yakın çevreleme işleviyle ilişkilidir
  • bir değişken bildirimi için kapalı fonksiyon yoksa, global kapsamdır

Bu nedenle, işlevler dışındaki bloklar yeni bir kapsam oluşturmaz. Bu, for-loop'ların neden dış kapsamdaki değişkenlerin üzerine yazıldığını açıklar:

var i = 10, v = 10;
for (var i = 0; i < 5; i++) { var v = 5; }
console.log(i, v);
// output 5 5

Bunun yerine işlevleri kullanma:

var i = 10, v = 10;
$.each([0, 1, 2, 3, 4], function(i) { var v = 5; });
console.log(i,v);
// output 10 10

İlk örnekte, hiçbir blok kapsamı bulunmadığından, başlangıçta bildirilen değişkenlerin üzerine yazılmıştır. İkinci örnekte, işlev nedeniyle yeni bir kapsam vardı, bu nedenle başlangıçta bildirilen değişkenler GÖSTERİLDİ ve üzerine yazılmadı.

JavaScript kapsamı açısından bilmeniz gereken hemen hemen hepsi bu, ancak:

Böylece JavaScript kapsamının her zaman sezgisel olmasa da aslında son derece basit olduğunu görebilirsiniz. Dikkat edilmesi gereken birkaç nokta:

  • var bildirimleri kapsamın en üstünde yer alır. Bu, var bildirimi nerede olursa olsun, derleyiciye varlığın kendisi üstte olduğu anlamına gelir
  • aynı kapsamdaki birden çok değişken bildirimi birleştirilir

Yani bu kod:

var i = 1;
function abc() {
  i = 2;
  var i = 3;
}
console.log(i);     // outputs 1

şuna eşittir:

var i = 1;
function abc() {
  var i;     // var declaration moved to the top of the scope
  i = 2;
  i = 3;     // the assignment stays where it is
}
console.log(i);

Bu karşı sezgisel görünebilir, ancak zorunlu bir dil tasarımcısı açısından mantıklıdır.


5

Modern Js, ES6 +, ' const' ve ' let'

Diğer büyük diller gibi, oluşturduğunuz her değişken için blok kapsamayı kullanmanız gerekir. varolduğunu eskimiş . Bu, kodunuzu daha güvenli ve daha bakımlı hale getirir.

constvakaların% 95'inde kullanılmalıdır . Değişken başvurusunun değişmemesi için bunu yapar . Dizi, nesne ve DOM düğümü özellikleri değişebilir ve olması gerekir const.

letyeniden atanması beklenen herhangi bir değişken için kullanılmalıdır. Buna bir for döngüsü dahil. Değeri başlatmanın ötesinde değiştirirseniz, kullanın let.

Blok kapsamı, değişkenin yalnızca bildirildiği köşeli parantez içinde kullanılabileceği anlamına gelir. Bu, kapsamınızda oluşturulan anonim işlevler dahil olmak üzere dahili kapsamlara kadar uzanır.


3

Bu meraklı örneği deneyin. Aşağıdaki örnekte, a 0 değerinde başlatılmış bir sayısal olsaydı, 0 ve sonra 1 görürsünüz. A dışında bir nesnedir ve javascript f1 öğesinin bir kopyasından ziyade bir işaretçisini geçirir. Sonuç, aynı uyarıyı her iki seferde de almanızdır.

var a = new Date();
function f1(b)
{
    b.setDate(b.getDate()+1);
    alert(b.getDate());
}
f1(a);
alert(a.getDate());

3

JS'de yalnızca işlev kapsamları vardır. Kapsamları engellemeyin! Neyin kaldırıldığını da görebilirsiniz.

var global_variable = "global_variable";
var hoisting_variable = "global_hoist";

// Global variables printed
console.log("global_scope: - global_variable: " + global_variable);
console.log("global_scope: - hoisting_variable: " + hoisting_variable);

if (true) {
    // The variable block will be global, on true condition.
    var block = "block";
}
console.log("global_scope: - block: " + block);

function local_function() {
    var local_variable = "local_variable";
    console.log("local_scope: - local_variable: " + local_variable);
    console.log("local_scope: - global_variable: " + global_variable);
    console.log("local_scope: - block: " + block);
    // The hoisting_variable is undefined at the moment.
    console.log("local_scope: - hoisting_variable: " + hoisting_variable);

    var hoisting_variable = "local_hoist";
    // The hoisting_variable is now set as a local one.
    console.log("local_scope: - hoisting_variable: " + hoisting_variable);
}

local_function();

// No variable in a separate function is visible into the global scope.
console.log("global_scope: - local_variable: " + local_variable);

(cevabın gönderilmesinden bu yana uzun süre) Kapsamı engelle; developer.mozilla.org/tr/docs/Web/JavaScript/Reference/…
Bob

2

Anladığım kadarıyla 3 kapsam var: küresel kapsam, küresel olarak mevcut; bloklar ne olursa olsun tüm fonksiyonlar için yerel kapsam; ve blok kapsamı, yalnızca üzerinde kullanıldığı blok, ifade veya ifade için kullanılabilir. Genel ve yerel kapsam, bir işlev içinde veya dışında 'var' anahtar sözcüğüyle ve blok kapsamı 'let' anahtar sözcüğüyle belirtilir.

Yalnızca küresel ve yerel kapsam olduğuna inananlar için, lütfen Mozilla'nın neden JS'deki blok kapsamının nüanslarını açıklayan tüm bir sayfaya sahip olacağını açıklayın.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let


2

Henüz açık uç kodlayıcıların sık sık karşılaştığı çok yaygın bir sorun, HTML'deki bir satır içi olay işleyicisi tarafından görülebilen kapsamdır - örneğin,

<button onclick="foo()"></button>

Bir on*özniteliğin başvurabileceği değişkenlerin kapsamı şunlardan biri olmalıdır :

  • global (çalışan satır içi işleyiciler neredeyse her zaman global değişkenlere başvurur)
  • belgenin bir özelliği (ör. querySelectorbağımsız bir değişken olarak document.querySelector; nadir)
  • işleyicinin bağlı olduğu elemanın bir özelliği (yukarıdaki gibi; nadir)

Aksi takdirde, işleyici çağrıldığında ReferenceError alırsınız. Bu nedenle, örneğin, satır içi işleyici içinde tanımlanan bir işleve başvuruyorsa window.onloadveya $(function() {başvuru başarısız olursa, çünkü satır içi işleyici yalnızca genel kapsamdaki değişkenlere başvurabilir ve işlev genel değildir:

Özellikleri documentve işleyici içi yükleyiciler çağrılır için de içi işleyicileri içinde bağımsız değişkenler olarak ifade edilebilir bağlı olan elementin özelliklerinin içinde iki withblok için, bir documentelemanın için bir. Bu işleyicilerin içindeki değişkenler kapsam zinciri son derece sezgisel değildir ve çalışan bir olay işleyicisi muhtemelen küresel olmak için bir işlev gerektirecektir (ve gereksiz küresel kirlilikten kaçınılmalıdır ).

Satır içi işleyicilerin içindeki kapsam zinciri çok garip olduğu ve satır içi işleyicilerin çalışması için küresel kirliliğe ihtiyaç duyduklarından ve satır içi işleyiciler bazen bağımsız değişkenleri geçerken çirkin dizelerden kaçmayı gerektirdiğinden, bunlardan kaçınmak daha kolaydır. Bunun yerine, addEventListenerHTML işaretlemesinden ziyade Javascript (gibi ) kullanarak olay işleyicileri ekleyin .


Farklı bir notta, <script>en üst düzeyde çalışan normal etiketlerin aksine , ES6 modüllerinin içindeki kod kendi özel kapsamında çalışır. Normal bir <script>etiketin üstünde tanımlanan bir değişken globaldir, bu nedenle aşağıdaki <script>gibi diğer etiketlerde referans verebilirsiniz :

Ancak ES6 modülünün en üst seviyesi global değildir . ES6 modülünün üstünde bildirilen bir değişken, değişken açıkça exportdüzenlenmedikçe veya global nesnenin bir özelliğine atanmadıkça yalnızca bu modülün içinde görünür .

Bir ES6 modülünün en üst seviyesi, normalde en üst seviyedeki IIFE'nin iç seviyesine benzer <script>. Modül, global olan herhangi bir değişkene başvurabilir ve modül açıkça bunun için tasarlanmadığı sürece hiçbir şey modülün içindeki herhangi bir şeye başvuramaz.


1

JavaScript'te iki tür kapsam vardır:

  • Yerel kapsam
  • Global kapsam

Below fonksiyonunun yerel bir kapsam değişkeni vardır carName. Ve bu değişkene fonksiyonun dışından erişilemez.

function myFunction() {
    var carName = "Volvo";
    alert(carName);
    // code here can use carName
}

Aşağıdaki Sınıf bir Global kapsam değişkenine sahiptir carName. Ve bu değişkene sınıfın her yerinden erişilebilir.

class {

    var carName = " Volvo";

    // code here can use carName

    function myFunction() {
        alert(carName);
        // code here can use carName 
    }
}

1

ES5 ve öncesi:

Javascript'teki değişkenler başlangıçta (pre ES6) lexically fonksiyon kapsamı kapsamına alınmıştır. Sözcüksel olarak kapsamlandırılmış terimi, koda 'bakarak' değişkenlerin kapsamını görebileceğiniz anlamına gelir.

varAnahtar kelimeyle bildirilen her değişken işleve dahil edilir. Ancak, bu işlev içinde başka işlev bildirilirse, bu işlevlerin dış işlevlerin değişkenlerine erişimi olur. Buna kapsam zinciri denir . Aşağıdaki şekilde çalışır:

  1. Bir işlev değişken bir değeri çözmek istediğinde, önce kendi kapsamına bakar. Bu işlev gövdesidir, yani süslü parantezler {} arasındaki her şeydir ( bu kapsamdaki diğer işlevler içindeki değişkenler hariç ).
  2. İşlev gövdesinin içindeki değişkeni bulamazsa zincire çıkacak ve işlevin tanımlandığı işlevdeki değişken kapsamına bakacaktır . Sözcüksel kapsamla kastedilen budur, kodda bu işlevin tanımlandığı yeri görebilir ve bu nedenle kapsam zincirini yalnızca koda bakarak belirleyebiliriz.

Misal:

// global scope
var foo = 'global';
var bar = 'global';
var foobar = 'global';

function outerFunc () {
 // outerFunc scope
 var foo = 'outerFunc';
 var foobar = 'outerFunc';
 innerFunc();
 
 function innerFunc(){
 // innerFunc scope
  var foo = 'innerFunc';
  console.log(foo);
  console.log(bar);
  console.log(foobar);
  }
}

outerFunc();

Ne değişkenleri oturum çalışırken olur foo, barve foobarkonsola şudur:

  1. Foo'yu konsola kaydetmeye çalışırız, foo işlevin içinde bulunabilir innerFunc. Bu nedenle, foo değeri dizeye çözümlenir innerFunc.
  2. Çubuğu konsola kaydetmeye çalışırız, işlevin içinde çubuk bulunamaz innerFunc. Bu nedenle, kapsam zincirine tırmanmamız gerekiyor . İlk olarak, işlevin innerFunctanımlandığı dış işleve bakarız . Bu işlev outerFunc. Bu kapsamda outerFunc'outerFunc' dizesini tutan değişken çubuğu bulabiliriz.
  3. foobar innerFunc içinde bulunamıyor. . Bu nedenle, kapsam zincirini innerFunc kapsamına tırmanmamız gerekir . Burada da bulunamaz, başka bir seviyeye küresel kapsamda tırmanıyoruz (yani en dıştaki kapsam). Burada 'global' dizesini tutan foobar değişkenini buluyoruz. Kapsam zincirine çıktıktan sonra değişkeni bulamazsa, JS motoru bir referenceError atar .

ES6 (ES 2015) ve daha eski sürümler:

Sözcüksel kapsam ve skopekinin aynı kavramları hala geçerlidir ES6. Bununla birlikte, değişkenleri bildirmenin yeni yolları tanıtıldı. Aşağıdakiler var:

  • let: blok kapsamı değişkeni oluşturur
  • const: yeniden başlatılması gereken ve yeniden atanamayan bir blok kapsamındaki değişken oluşturur

Arasındaki en büyük fark varve let/ constolmasıdır varfonksiyonu ise kapsamlı olan let/ constblok kapsamlı bulunmaktadır. İşte bunu gösteren bir örnek:

let letVar = 'global';
var varVar = 'global';

function foo () {
  
  if (true) {
    // this variable declared with let is scoped to the if block, block scoped
    let letVar = 5;
    // this variable declared with let is scoped to the function block, function scoped
    var varVar = 10;
  }
  
  console.log(letVar);
  console.log(varVar);
}


foo();

Yukarıdaki örnekte, letVar değeri, global olarak günlüğe kaydeder çünkü bildirilen değişkenler letblok kapsamlıdır. İlgili bloklarının dışında kalmayı bırakırlar, bu nedenle değişkene if bloğunun dışında erişilemez.


0

EcmaScript5'te esas olarak yerel kapsam ve küresel kapsam olmak üzere iki kapsam vardır, ancak EcmaScript6'da esas olarak üç kapsamımız vardır, yerel kapsam, global kapsam ve blok kapsamı adı verilen yeni bir kapsam .

Blok kapsamı örneği: -

for ( let i = 0; i < 10; i++)
{
 statement1...
statement2...// inside this scope we can access the value of i, if we want to access the value of i outside for loop it will give undefined.
}

0

ECMAScript 6, let ve const anahtar kelimelerini tanıttı. Bu anahtar kelimeler var anahtar sözcüğü yerine kullanılabilir. Var anahtar sözcüğünün aksine, let ve const anahtar sözcükleri, blok deyimleri içindeki yerel kapsam bildirimini destekler.

var x = 10
let y = 10
const z = 10
{
  x = 20
  let y = 20
  const z = 20
  {
    x = 30
    // x is in the global scope because of the 'var' keyword
    let y = 30
    // y is in the local scope because of the 'let' keyword
    const z = 30
    // z is in the local scope because of the 'const' keyword
    console.log(x) // 30
    console.log(y) // 30
    console.log(z) // 30
  }
  console.log(x) // 30
  console.log(y) // 20
  console.log(z) // 20
}

console.log(x) // 30
console.log(y) // 10
console.log(z) // 10

0

Kabul edilen cevabı gerçekten seviyorum ama bunu eklemek istiyorum:

Scope, bildirilen tüm tanımlayıcıların (değişkenler) bir arama listesini toplar ve saklar ve bunların şu anda yürütülen kod için nasıl erişilebilir olduğuna ilişkin katı kurallar uygular.

Kapsam, değişkenleri tanımlayıcı adlarına göre aramak için bir dizi kuraldır.

  • Bir değişken hemen kapsamda bulunamazsa, Motor bulunana kadar veya en dıştaki (diğer bir deyişle küresel) kapsama ulaşılana kadar devam eden bir sonraki dış kapsama alanına başvurur.
  • Bir değişkenin (tanımlayıcının) nerede ve nasıl aranabileceğini belirleyen kurallar kümesidir. Bu arama, bir LHS (sol taraf) referansı olan değişkene atama veya bir RHS (sağ taraf) referansı olan değerinin alınması amacıyla olabilir. .
  • LHS referansları atama işlemlerinden kaynaklanır. Kapsamla ilgili atamalar = işleciyle ya da (atama) işlev parametrelerine argümanlar iletilerek gerçekleşebilir.
  • JavaScript motoru önce kodu çalıştırmadan önce derler ve bu şekilde var a = 2; iki ayrı adımda: 1.. İlk olarak, bu kapsamda beyan etmek için var a. Bu, kod yürütülmesinden önce, başlangıçta gerçekleştirilir. 2. Daha sonra, değişkeni aramak için a = 2 (LHS referansı) ve bulunursa ona atayın.
  • Hem LHS hem de RHS referans aramaları şu anda yürütülen kapsamda başlar ve gerekiyorsa (yani orada aradıklarını bulamazlar), iç içe geçmiş, bir kapsam (zemin) ) bir kerede, tanımlayıcıyı arayarak, global (en üst kat) 'a ulaşıncaya ve durup buluncaya kadar bulun. Doldurulmamış RHS başvuruları ReferenceError öğesinin atılmasına neden olur. Doldurulmamış LHS başvuruları, bu adın otomatik olarak, dolaylı olarak oluşturulmuş bir genel (Sıkı Modda değilse) veya bir ReferenceError (Sıkı Modda ise) ile sonuçlanır.
  • kapsam, her birinin tanımlayıcıların (değişkenler, işlevler) bildirildiği bir kap veya kova olarak hareket ettiği bir dizi “baloncuk” dan oluşur. Bu kabarcıklar birbirinin içine düzgünce yerleşir ve bu yuvalama yazar zamanında tanımlanır.

-3

JavaScript'te iki tür kapsam vardır.

  1. Global kapsam : global kapsamda ilan edilen değişken, programın herhangi bir yerinde sorunsuz bir şekilde kullanılabilir. Örneğin:

    var carName = " BMW";
    
    // code here can use carName
    
    function myFunction() {
         // code here can use carName 
    }
  2. İşlevsel kapsam veya Yerel kapsam : bu kapsamda bildirilen değişken yalnızca kendi işlevinde kullanılabilir. Örneğin:

    // code here can not use carName
    function myFunction() {
       var carName = "BMW";
       // code here can use carName
    }
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.