scope - ما الفرق بين استخدام "let" و "var" لإعلان متغير في JavaScript؟




ecmascript-6 (23)

قدم ECMAScript 6 بيان let . سمعت أنه وصف بأنه متغير "محلي" ، لكنني لا أزال غير متأكد تمامًا من سلوكه بشكل مختلف عن الكلمة الرئيسية var .

ما هي الاختلافات؟ متى يجب let باستخدام var ؟


Answers

قد تظهر الدالتان التاليتان الفرق:

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
}

كما ذكر أعلاه:

الفرق هو النطاق. varوراقب إلى أقرب كتلة وظيفة و letوراقب إلى أقرب كتلة أرفق ، والتي يمكن أن تكون أصغر من كتلة وظيفة. كلاهما عالميان إذا كانا خارج أي كتلة. دعنا نرى مثالاً:

مثال 1:

في كلا المثالين لدي وظيفة myfunc. myfuncيحتوي على متغير myvarيساوي 10. في أول مثال أقوم myvarبفحصه إذا كان يساوي 10 ( myvar==10). إذا كانت الإجابة نعم ، فأنا أعلن عن متغير myvar(الآن لدي متغيرين من myvar) باستخدام varكلمة أساسية وقم بتعيينها كقيمة جديدة (20). في السطر التالي أقوم بطباعة قيمته على وحدة التحكم الخاصة بي. بعد الكتلة الشرطية ، أقوم مرة أخرى بطباعة قيمة myvarوحدة التحكم الخاصة بي. إذا نظرت إلى مخرجات myfunc، فإن myvarالقيمة تساوي 20.

مثال 2 : في المثال الثاني الخاص بي بدلاً من استخدام varالكلمة الأساسية في المجموعة الشرطية الخاصة بي ، أعلن myvarباستخدام letالكلمة الأساسية. الآن عندما أتصل myfuncأحصل على نتيجتين مختلفتين: myvar=20و myvar=10.

إذاً ، الفرق بسيط جداً أي نطاقه.


الفرق في scope المتغيرات المعلن عنها مع كل منها.

في الواقع ، هناك عدد من النتائج المفيدة للاختلاف في النطاق:

  1. letالمتغيرات مرئية فقط في اقرب كتلة مغلقة ( { ... }).
  2. letتكون المتغيرات قابلة للاستخدام فقط في أسطر الكود التي تحدث بعد إعلان المتغير (على الرغم من أنه يتم رفعه !).
  3. letلا يجوز إعادة تعريف المتغيرات بواسطة لاحقة varأو let.
  4. letالمتغيرات العمومية لا تضاف إلى windowالكائن العام.
  5. letالمتغيرات هي سهلة الاستخدام مع إغلاق (أنها لا تسبب ظروف السباق ).

القيود المفروضة من خلال letالحد من وضوح المتغيرات وزيادة احتمالية حدوث اصطدامات اسم غير متوقعة في وقت مبكر. هذا يجعل من السهل تتبع المتغيرات والسبب فيها ، بما في ذلك reachability (المساعدة في استعادة الذاكرة غير المستخدمة).

ونتيجة لذلك ، letتقل احتمالية تسبب المتغيرات في حدوث مشكلات عند استخدامها في البرامج الكبيرة أو عندما يتم دمج الأطر المطورة بشكل مستقل بطرق جديدة وغير متوقعة.

varقد يكون مفيدًا إذا كنت متأكدًا من أنك تريد تأثير الربط المفرد عند استخدام الإغلاق في حلقة (# 5) أو لإعلان المتغيرات العامة المرئية خارجياً في التعليمات البرمجية (# 4). varقد يحل محل الاستخدام للصادرات إذا تم exportترحيلها من مساحة التحويل إلى لغة أساسية.

أمثلة

1. عدم الاستخدام خارج أقرب كتلة مرفقة: سيؤدي هذا الكود من التعليمات البرمجية إلى إلقاء خطأ مرجعي نظرًا لأن الاستخدام الثاني xيحدث خارج الكتلة التي تم الإعلان عنها باستخدام let:

{
    let x = 1;
}
console.log(`x is ${x}`);  // ReferenceError during parsing: "x is not defined".

في المقابل ، نفس المثال مع varالأعمال.

2. لا يوجد استخدام قبل الإعلان:
هذا القالب من التعليمات البرمجية سيلقي ReferenceErrorقبل تشغيل التعليمة البرمجية لأنه xيتم استخدامه قبل إعلانه:

{
    x = x + 1;  // ReferenceError during parsing: "x is not defined".
    let x;
    console.log(`x is ${x}`);  // Never runs.
}

في المقابل ، المثال نفسه مع varparses ويدير دون إلقاء أي استثناءات.

3. لا يوجد redeclaration: يوضح التعليمة البرمجية التالية أنه letقد لا يتم redeclared متغير مع تعريفه فيما بعد:

let x = 1;
let x = 2;  // SyntaxError: Identifier 'x' has already been declared

4. globals لا تعلق على 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. سهل الاستخدام مع الإغلاق: المتغيرات المعلنة مع varلا تعمل بشكل جيد مع إغلاق داخل حلقات. وهنا حلقة بسيطة تخرج تسلسل القيم التي لدى المتغير iفي نقاط زمنية مختلفة:

for (let i = 0; i < 5; i++) {
    console.log(`i is ${i}`), 125/*ms*/);
}

على وجه التحديد ، هذه النواتج:

i is 0
i is 1
i is 2
i is 3
i is 4

في JavaScript ، غالبًا ما نستخدم المتغيرات في وقت لاحق بكثير من وقت إنشائها. عندما نوضح ذلك بتأخير الإخراج مع إغلاق الإغلاق إلى setTimeout:

for (let i = 0; i < 5; i++) {
    setTimeout(_ => console.log(`i is ${i}`), 125/*ms*/);
}

... يبقى الناتج دون تغيير طالما أننا نتمسك به let. في المقابل ، إذا استخدمنا var iبدلاً من ذلك:

for (var i = 0; i < 5; i++) {
    setTimeout(_ => console.log(`i is ${i}`), 125/*ms*/);
}

... تتسبب الحلقة بشكل غير متوقع في "i 5" خمس مرات:

i is 5
i is 5
i is 5
i is 5
i is 5

الاختلاف الرئيسي هو اختلاف النطاق ، بينما يمكن أن يكون متاحًا فقط داخل النطاق الذي تم الإعلان عنه ، مثل في حلقة for ، يمكن الوصول إلى var خارج الحلقة على سبيل المثال. من الوثائق في MDN (أمثلة أيضًا من MDN):

يسمح لك بتعريف المتغيرات التي تكون محدودة في النطاق إلى الكتلة أو العبارة أو التعبير الذي يتم استخدامه. هذا على عكس الكلمة الرئيسية var ، التي تحدد متغيرًا عالميًا ، أو محليًا إلى وظيفة بأكملها بغض النظر عن نطاق المنع.

المتغيرات المعلنة عن طريق السماح لنطاق لها الكتلة التي يتم تعريفها ، وكذلك في أي كتل فرعية الواردة. بهذه الطريقة ، دع العمل يشبه إلى حد كبير var . والفرق الرئيسي هو أن نطاق متغير var هو دالة الإحاطة بأكملها:

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
}`

في المستوى الأعلى من البرامج والوظائف ، دعونا ، على خلاف var ، لا يقوم بإنشاء خاصية على الكائن العام. فمثلا:

var x = 'global';
let y = 'global';
console.log(this.x); // "global"
console.log(this.y); // undefined

عند استخدامها داخل كتلة ، اترك حدود نطاق المتغير لهذه الكتلة. لاحظ الفرق بين var الذي يكون نطاقه داخل الدالة حيث يتم الإعلان عنه.

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

لا تنس أيضًا ميزة ECMA6 ، لذا فهي غير مدعومة بالكامل حتى الآن ، لذلك فمن الأفضل نقلها دائمًا إلى ECMA5 باستخدام بابل الخ ... لمزيد من المعلومات حول زيارة موقع babel


يبدو أيضًا أنه ، على الأقل في Visual Studio 2015 ، TypeScript 1.5 ، يسمح "var" بإعلانات متعددة لنفس اسم المتغير في كتلة ، و "let" لا.

لن يؤدي ذلك إلى إنشاء خطأ في الترجمة:

var x = 1;
var x = 2;

هذا سوف:

let x = 1;
let x = 2;

دعونا هو جزء من es6. هذه الوظائف سوف تشرح الفرق بطريقة سهلة.

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
}

يفتقد الجواب المقبول إلى نقطة:

{
  let a = 123;
};

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

إليك شرحًا حول let للكلمة الرئيسية ببعض الأمثلة.

اسمحوا يعمل يشبه إلى حد كبير فار. والفرق الرئيسي هو أن نطاق متغير var هو دالة الإحاطة بأكملها

يوضح هذا الجدول على موقع Wikipedia أي المستعرضات تدعم Javascript 1.7.

لاحظ أن مستعرضات Mozilla و Chrome فقط يدعمان ذلك. IE ، سفاري ، وربما الآخرين لا.


هناك بعض الاختلافات الطفيفة - فلنفرض أن نطاق الفحص يتصرف على نحو أكثر مثل إجراء فحص متغير في أكثر أو أقل من أي لغة أخرى.

على سبيل المثال ، فإنه يشير إلى الكتلة المغلقة ، فهي غير موجودة قبل أن يتم الإعلان عنها ، إلخ.

ومع ذلك ، تجدر الإشارة إلى أن let هو جزء فقط من تطبيقات جافا سكريبت الأحدث ولديها درجات متفاوتة من دعم المتصفح .



var هو النطاق العالمي (رافعة) المتغير.

letو constهو نطاق كتلة.

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


تحقق من هذا الرابط في MDN

let x = 1;

if (x === 1) {
let x = 2;

console.log(x);
// expected output: 2
}

console.log(x);
// expected output: 1

نطاق وظيفة نطاق VS:

والفرق الرئيسي بين varو letهو أن المتغيرات أعلن مع varو ظيفة راقب . في حين أن الوظائف المعلنة مع letهي خاصة بتطبيق كتلة . فمثلا:

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 

المتغيرات مع var:

عندما testVarيتم استدعاء الوظيفة الأولى var، لا يزال يمكن الوصول إلى المتغير foo ، المُعلن عنه ، خارج ifالبيان. fooسيكون هذا المتغير متاحًا في كل مكان ضمن نطاق testVar الوظيفة .

المتغيرات مع let:

عندما testLetيتم استدعاء الوظيفة الثانية let، يمكن الوصول إلى شريط المتغير ، الذي تم التصريح به ، داخل ifالبيان فقط. لأن المتغيرات التي تم التصريح عنها letهي كتلة محددة (حيث يكون الكود هو الكود بين الأقواس المتعرجة على سبيل المثال if{}، for{}، function{}).

let المتغيرات لا ترفع:

وثمة فرق آخر بين varو letهو المتغيرات مع المعلن مع let عدم الحصول على رفع . مثال على ذلك هو أفضل طريقة لتوضيح هذا السلوك:

المتغيرات مع let عدم الحصول على رافعة:

console.log(letVar);

let letVar = 10;
// referenceError, the variable doesn't get hoisted

المتغيرات مع var ما يحصل رفعت:

console.log(varVar);

var varVar = 10;
// logs undefined, the variable gets hoisted

letلا تلتزم جلوبل بما windowيلي:

لا يتم إضافة متغير تم التصريح به letفي النطاق العالمي (وهو رمز غير موجود في إحدى الوظائف) كخاصية على windowالكائن العام. على سبيل المثال (هذا الرمز في النطاق العالمي):

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


متى يجب letاستخدام أكثر var؟

استخدام letأكثر varكلما استطعت لأنه راقب ببساطة أكثر تحديدا. هذا يقلل من تعارض التسمية المحتملة التي يمكن أن تحدث عند التعامل مع عدد كبير من المتغيرات. varيمكن استخدامها عندما تريد أن يكون المتغير الشامل صريحًا على windowالكائن (فكر دائمًا بعناية إذا كان ذلك ضروريًا حقًا).


في ما يلي مثال للإضافة إلى ما كتبه الآخرون من قبل. لنفترض أنك تريد إنشاء صفيف من الدالات ، adderFunctions ، حيث تأخذ كل دالة وسيطة Number واحدة وترجع مجموع الوسيطة وفهرس الدالة في الصفيف. لن تعمل محاولة إنشاء adderFunctions باستخدام حلقة باستخدام الكلمة الرئيسية var بالطريقة التي قد يتوقعها شخص ما بسذاجة:

// 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

لا تؤدي العملية أعلاه إلى إنشاء مجموعة من الدالات المطلوبة لأن نطاق i يتجاوز نطاق التكرار for بالكتلة التي تم إنشاء كل دالة فيها. بدلاً من ذلك ، في نهاية الحلقة ، يشير i في كل إغلاق إلى قيمة i في نهاية الحلقة (1000) لكل وظيفة مجهولة في adderFunctions . هذا ليس ما أردناه على الإطلاق: لدينا الآن مجموعة من 1000 وظيفة مختلفة في الذاكرة مع نفس السلوك بالضبط. وإذا قمنا في وقت لاحق بتحديث قيمة i ، سوف تؤثر هذه الطفرة على كل adderFunctions .

ومع ذلك ، يمكننا إعادة المحاولة باستخدام الكلمة الرئيسية let :

// 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

هذه المرة ، يتم ارتداد i على كل تكرار للحلقة. تحتفظ كل دالة الآن بقيمة i في وقت إنشاء الدالة ، وتتصرف adderFunctions كما هو متوقع.

الآن ، صورة تمزج بين السلوكين ، وربما ستعرف لماذا لا يوصى بخلط الأحدث و const مع const الأقدم في نفس النص. يمكن أن يؤدي ذلك إلى بعض الشفرات المربكة بشكل مذهل.

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

لا تدع هذا يحصل لك. استخدام لنتير.

ملاحظة: هذا مثال تعليمي يهدف إلى إظهار var/ letالسلوك في الحلقات وإغلاق الوظيفة التي يسهل فهمها أيضًا. ستكون هذه طريقة مروعة لإضافة أرقام. لكن التقنية العامة لالتقاط البيانات في إغلاق وظيفة مجهولة الهوية قد تصادف في العالم الحقيقي في سياقات أخرى. YMMV.


في ما يلي مثال للفرق بين الاثنين (الدعم الذي بدأ للتو على chrome):

كما ترى ، لا يزال متغير var j له قيمة خارج نطاق الحلقة (Block Scope) ، ولكن متغير let i غير معرف خارج نطاق الحلقة.

"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);


let أيضا يمكن استخدامها لتجنب المشاكل مع الإغلاق. وهو يربط قيمة جديدة بدلاً من الاحتفاظ بمرجع قديم كما هو موضح في الأمثلة أدناه.

DEMO

for(var i = 1; i < 6; i++) {
  document.getElementById('my-element' + i)
    .addEventListener('click', function() { alert(i) })
}

يوضح الكود أعلاه مشكلة إغلاق جافا سكريبت الكلاسيكية. يتم تخزين المرجع إلى متغير i في إغلاق معالج النقر ، بدلاً من القيمة الفعلية لـ i .

سيشير كل معالج نقرة منفرد إلى نفس الكائن نظرًا لوجود كائن عداد واحد يحمل 6 حتى تحصل على ستة لكل نقرة.

الحل العام هو التفاف هذا في دالة المجهولة وتمرير i كوسيطة. يمكن أيضًا تجنب مثل هذه المشكلات من خلال استخدام بدلاً من ذلك var كما هو موضح في التعليمة البرمجية أدناه.

DEMO (تم اختباره في Chrome وفايرفوكس 50)

'use strict';

for(let i = 1; i < 6; i++) {
  document.getElementById('my-element' + i)
    .addEventListener('click', function() { alert(i) })
}

let أمر مثير للاهتمام ، لأنه يسمح لنا بفعل شيء كالتالي:

(() => {
    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++);
            }
        }
    }
})();

مما يؤدي إلى عد [0 ، 7].

بينما

(() => {
    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++);
            }
        }
    }
})();

التهم فقط [0 ، 1].


إذا قرأت المواصفات الحق في ذلك الحين let ولله الحمد كما يمكن الاستعانة بها لتجنب ظائف استحضار الذات استخدامها لمحاكاة أعضاء الوحيد الخاص - نمط تصميم شعبية أن يقلل قراءة رمز، ويعقد التصحيح، أن يضيف أي رمز الحماية الحقيقية أو أي منفعة أخرى - ربما باستثناء إرضاء شخص ما الرغبة في الدلالات ، لذلك توقف عن استخدامه. / خرف

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

راجع " محاكاة واجهات خاصة "


عند استخدام let

تقوم letالكلمة الرئيسية بإرفاق البيان المتغير بنطاق أي كتلة (شائعًا { .. }زوجًا) يتم تضمينها فيه. وبعبارة أخرى ، تقوم بشكل letضمني باختراق أي نطاق لبيانه المتغير.

letلا يمكن الوصول إلى المتغيرات في windowالكائن لأنه لا يمكن الوصول إليها عالميًا.

function a(){
    { // this is the Max Scope for let variable
        let x = 12;
    }
    console.log(x);
}
a(); // Uncaught ReferenceError: x is not defined

عند استخدام var

var والمتغيرات في ES5 لها نطاقات في وظائف تعني أن المتغيرات صحيحة داخل الوظيفة وليست خارج الوظيفة نفسها.

varيمكن الوصول إلى المتغيرات في windowالكائن لأنه لا يمكن الوصول إليها عالميًا.

function a(){ // this is the Max Scope for var variable
    { 
        var x = 12;
    }
    console.log(x);
}
a(); // 12

إذا كنت تريد معرفة المزيد تابع القراءة أدناه

واحد من أشهر الأسئلة المقابلة حول نطاق يمكن أن تكفي أيضا استخدام الدقيق letوعلى varالنحو التالي ؛

عند استخدام let

for (let i = 0; i < 10 ; i++) {
    setTimeout(
        function a() {
            console.log(i); //print 0 to 9, that is literally AWW!!!
        }, 
        100 * i);
}

ويرجع ذلك إلى أنه عند استخدام letالتكرار ، يتم ضبط المتغير ويكون له نسخة خاصة به.

عند استخدام var

for (var i = 0; i < 10 ; i++) {
    setTimeout(
        function a() {
            console.log(i); //print 10 times 10
        }, 
        100 * i);
}

هذا لأنه عند استخدام var، لكل تكرار تكرار المتغير الذي تم تعيينه ولديه نسخة مشتركة.


في السابق لم يكن هناك سوى نطاقات في JavaScript ، أي وظيفية وعالمية. من خلال letالكلمة الأساسية "JavaScript" ، فقد أدخلت الآن block-levelمتغيرات.

للحصول على فهم كامل للكلمة الأساسية "let" ، ES6: "let" ستُستخدم الكلمة الرئيسية لإعلام المتغير في JavaScript .


ما هو الفرق بين let و var ؟

  • يعرف المتغير الذي يتم تعريفه باستخدام جملة var طوال الوظيفة التي تم تعريفها بها ، من بداية الوظيفة. (*)
  • يعرف المتغير المحدد باستخدام عبارة let فقط في الكتلة التي يتم تعريفها بها ، من لحظة تعريفها فصاعدا. (**)

لفهم الفرق ، ضع في اعتبارك الشفرة التالية:

// 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

هنا ، يمكننا أن نرى أن المتغير j بنا معروف فقط في الحلقة الأولى ، ولكن ليس قبل وبعد. ومع ذلك ، فإن المتغير i بنا معروف في الوظيفة بأكملها.

أيضًا ، ضع في اعتبارك أن المتغيرات التي تم تحديد نطاقها غير معروفة قبل أن يتم الإعلان عنها لأنها غير مرفوعة. لا يُسمح لك أيضًا بإعادة تعيين متغير الكتلة المحدد نفسه داخل المجموعة نفسها. وهذا يجعل المتغيرات ذات النطاق أقل عرضة للخطأ من المتغيرات ذات النطاق العالمي أو الوظيفي ، والتي يتم رفعها والتي لا تنتج أي أخطاء في حالة إعلانات متعددة.

هل هي آمنة لاستخدام let اليوم؟

قد يجادل بعض الناس بأننا في المستقبل سوف نستخدم فقط البيانات المسموح بها وبيانات var ستصبح قديمة. كتب غوغل جورو كايل سيمبسون مقالة متقنة جدا عن سبب هذا ليس هو الحال .

اليوم ، ومع ذلك ، هذا هو بالتأكيد ليس هو الحال. في الواقع ، نحن في الواقع بحاجة إلى أن نسأل أنفسنا ما إذا كان من الآمن استخدام بيان let . تعتمد الإجابة على هذا السؤال على بيئتك:

  • إذا كنت تكتب شفرة JavaScript من جانب الخادم ( Node.js ) ، فيمكنك استخدام العبارة let بأمان.

  • إذا كنت تكتب شفرة جافا سكريبت من جانب العميل وتستخدم أداة نقل (مثل Traceur ) ، فيمكنك استخدام العبارة let بأمان ، ولكن من المرجح أن يكون كودك أي شيء غير مثالي فيما يتعلق بالأداء.

  • إذا كنت تكتب شفرة جافا سكريبت من جانب العميل ولا تستخدم برنامج التحويل البرمجي ، فيجب التفكير في دعم المتصفح.

اليوم ، 8 يونيو 2018 ، لا تزال هناك بعض المتصفحات التي لا تدعم!

كيفية تتبع دعم المتصفح

للحصول على نظرة عامة محدّثة حول أي المتصفحات تدعم العبارة let في وقت قراءتك لهذه الإجابة ، انظر صفحة " Can I Use .

(*) يمكن تهيئة متغيرات النطاق العالمي والعملي واستخدامها قبل إعلانها لأن متغيرات جافا سكريبت يتم hoisted . هذا يعني أن الإعلانات تكون دائما في قمة النطاق.

(**) لا يتم رفع متغيرات كتلة النطاق


الآن أعتقد أن هناك مجالًا أفضل للمتغيرات إلى مجموعة من العبارات باستخدام 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
}

أعتقد أن الناس سيبدأون في استخدام السماح هنا بعد ذلك حتى يتمكنوا من تحديد نطاق مماثل في جافا سكريبت مثل لغات أخرى ، جافا ، سي # ، إلخ.

اعتاد الأشخاص الذين ليس لديهم فهم واضح حول تحديد النطاق في JavaScript على ارتكاب الخطأ سابقًا.

الرفع غير مدعوم باستخدام let.

مع إزالة هذه الأخطاء الموجودة في JavaScript.

ارجع إلى ES6 In Depth: دع و Const لفهمه بشكل أفضل.


يمكنك استخدام مكون السلسلة المفتوحة القابل لإعادة الاستخدام والمفتوح المصدر هذا لمعرفة ما إذا كان var عبارة عن سلسلة مع تجنب نسخها ولصقها.

أمثلة:

 isString(3) // => false
 isString('') // => true

أيضًا ، إليك كيفية تنفيذ isString في isString :

function isString(value) {return typeof value === 'string';}




javascript scope ecmascript-6 var let