javascript ما الغرض من الكلمة الرئيسية var ومتى يجب استخدامها(أو حذفها)؟




keyword ecmascript-5 (15)

لا تستخدم var !

var كان طريقة ما قبل ES6 لإعلان متغير. نحن الآن في المستقبل ، ويجب أن يكون الترميز على هذا النحو.

استخدم const let

يجب استخدام const لـ 95٪ من الحالات. فهو يجعله حتى لا يمكن تغيير المرجع المتغير ، وبالتالي يمكن تغيير خصائص المصفوفة والعناصر وعقد DOM ويجب أن تكون const .

يجب أن يتم استخدام أي متغير يتوقع أن يتم إعادة تعيينه. وهذا يشمل داخل حلقة. إذا كنت قد كتبت varName = بعد التهيئة ، استخدم let .

كلاهما يحتوي على نطاق فحص الكتلة ، كما هو متوقع في معظم اللغات الأخرى.

ملاحظة : تم طرح هذا السؤال من وجهة نظر ECMAScript الإصدار 3 أو 5. قد تصبح الإجابات قديمة مع إدخال ميزات جديدة في إصدار ECMAScript 6.

ما هي وظيفة الكلمة الرئيسية var في JavaScript بالضبط ، وما هو الفرق بين

var someNumber = 2;
var someFunction = function() { doSomething; }
var someObject = { }
var someObject.someProperty = 5;

و

someNumber = 2;
someFunction = function() { doSomething; }
someObject = { }
someObject.someProperty = 5;

؟

متى ستستخدم أحدهما ، ولماذا / ماذا يفعل؟


داخل الرمز ، إذا كنت تستخدم متغيرًا بدون استخدام var ، فإن ما يحدث هو وضع var varname تلقائيًا في النطاق العالمي ، على سبيل المثال:

someFunction() {
    var a = some_value; /*a has local scope and it cannot be accessed when this
    function is not active*/
    b = a; /*here it places "var b" at top of script i.e. gives b global scope or
    uses already defined global variable b */
}

هناك فرق

var x = 1 يحدد المتغير x في النطاق الحالي (سياق التنفيذ). إذا ظهر الإعلان في إحدى الدوال ، فسيتم الإعلان عن متغير محلي ؛ إذا كان في النطاق العالمي - يتم تعريف متغير عمومي.

x = 1 ، على الجانب الآخر ، هو مجرد تعيين خاصية. يحاول أولاً حل x ضد سلسلة النطاق. إذا وجدته في أي مكان في سلسلة النطاق ، فإنه ينفذ مهمة ؛ إذا لم يعثر على x ، فحينئذٍ فقط يقوم بإنشاء خاصية x على كائن عام (وهو كائن ذو مستوى أعلى في سلسلة نطاق).

الآن ، لاحظ أنه لا يعلن متغير عمومي ، فإنه ينشئ خاصية عمومية.

الفرق بين الاثنين دقيق ويمكن أن يكون مربكًا ما لم تفهم أن تعريفات المتغير تقوم أيضًا بإنشاء خصائص (فقط على كائن متغير) وأن كل خاصية في Javascript (well، ECMAScript) لها أعلام معينة تصف خصائصها - ReadOnly و DontEnum و DontDelete.

منذ تعريف متغير بإنشاء الخاصية مع علامة DontDelete ، الفرق بين var x = 1 و x = 1 (عند تنفيذها في النطاق العالمي) هو أن تعريف متغير واحد سابق - ينشئ الخاصية DontDelete'able ، والآخر لا . ونتيجة لذلك ، يمكن حذف الخاصية التي تم إنشاؤها عن طريق هذا الواجب الضمني من الكائن العام ، ولا يمكن حذف الخاصية السابقة - التي تم إنشاؤها من خلال الإعلان المتغير -.

ولكن هذه مجرد نظرية بالطبع ، وفي الواقع هناك اختلافات أكثر بين الاثنين ، بسبب الأخطاء المختلفة في التطبيقات (مثل تلك الموجودة في IE).

آمل أن يكون كل ذلك له معنى:)

[تحديث 2010/12/16]

في ES5 (ECMAScript 5 ؛ النسخة الخامسة من اللغة الموحدة مؤخراً) ، يوجد ما يسمى بـ "الوضع المقيد" - وهو وضع لغة تمكّن ، والذي يغير سلوك الواجبات غير المصرح بها بشكل طفيف. في الوضع المقيد ، يكون التعيين لمعرف غير معرف هو ReferenceError . وكان الأساس المنطقي لذلك هو الإمساك بالمهمات العرضية ، ومنع خلق خصائص عالمية غير مرغوبة. بدأت بعض المتصفحات الجديدة بالفعل في الحصول على دعم لوضع صارم. انظر ، على سبيل المثال ، جدول التوافق الخاص بي .


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

انظر السيناريو أدناه في العمل هنا في jsfiddle

a = 1;// Defined outside the function without var
var b = 1;// Defined outside the function with var
alert("Starting outside of all functions... \n \n a, b defined but c, d not defined yet: \n a:" + a + "\n b:" + b + "\n \n (If I try to show the value of the undefined c or d, console.log would throw 'Uncaught ReferenceError: c is not defined' error and script would stop running!)");

function testVar1(){
    c = 1;// Defined inside the function without var
    var d = 1;// Defined inside the function with var
    alert("Now inside the 1. function: \n a:" + a + "\n b:" + b + "\n c:" + c + "\n d:" + d);

    a = a + 5;
    b = b + 5;
    c = c + 5;
    d = d + 5;

    alert("After added values inside the 1. function: \n a:" + a + "\n b:" + b + "\n c:" + c + "\n d:" + d);
};


testVar1();
alert("Run the 1. function again...");
testVar1();

function testVar2(){
    var d = 1;// Defined inside the function with var
    alert("Now inside the 2. function: \n a:" + a + "\n b:" + b + "\n c:" + c + "\n d:" + d);

    a = a + 5;
    b = b + 5;
    c = c + 5;
    d = d + 5;

    alert("After added values inside the 2. function: \n a:" + a + "\n b:" + b + "\n c:" + c + "\n d:" + d);
};

testVar2();

alert("Now outside of all functions... \n \n Final Values: \n a:" + a + "\n b:" + b + "\n c:" + c + "\n You will not be able to see d here because then the value is requested, console.log would throw error 'Uncaught ReferenceError: d is not defined' and script would stop. \n ");
alert("**************\n Conclusion \n ************** \n \n 1. No matter declared with or without var (like a, b) if they get their value outside the function, they will preserve their value and also any other values that are added inside various functions through the script are preserved.\n 2. If the variable is declared without var inside a function (like c), it will act like the previous rule, it will preserve its value across all functions from now on. Either it got its first value in function testVar1() it still preserves the value and get additional value in function testVar2() \n 3. If the variable is declared with var inside a function only (like d in testVar1 or testVar2) it will will be undefined whenever the function ends. So it will be temporary variable in a function.");
alert("Now check console.log for the error when value d is requested next:");
alert(d);

استنتاج

  1. وبغض النظر عما إذا كان قد تم التصريح به باستخدام var أو بدونه (مثل a ، b) إذا كانت القيمة الخاصة بهم خارج الدالة ، فسيحتفظون بقيمتها وأي قيم أخرى يتم إضافتها داخل وظائف متنوعة من خلال النص البرمجي يتم الاحتفاظ بها.
  2. إذا تم التصريح عن المتغير بدون var داخل وظيفة (مثل c) ، فسوف يعمل مثل القاعدة السابقة ، فإنه سيحافظ على قيمته عبر جميع الوظائف من الآن فصاعدًا. إما أنها حصلت على القيمة الأولى في الدالة testVar1 () فإنها لا تزال تحافظ على القيمة وتحصل على قيمة إضافية في الدالة testVar2 ()
  3. إذا تم التصريح عن المتغير مع var داخل وظيفة فقط (مثل d في testVar1 أو testVar2) ، فسيتم تحديده عندما تنتهي الدالة. لذلك سيكون متغير مؤقت في وظيفة.

عندما يتم تنفيذ جافا سكريبت في متصفح ، فإن كل شفرتك محاطة ببيان مع ، مثل:

with (window) {
    //Your code
}

مزيد من المعلومات حول - with MDN

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

يأتي الفرق عندما لا تكون داخل النافذة مباشرة ، على سبيل المثال داخل وظيفة أو داخل كتلة.

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

والقاعدة الأساسية هي استخدام var دائمًا ، وإلا فإنك تخاطر بإدخال أخطاء بسيطة.

تحرير: بعد الانتقادات التي تلقيتها ، أود أن أؤكد على ما يلي:

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

إذا كنت في النطاق العالمي ، فلا فرق.

إذا كنت في إحدى الوظائف ، فحينئذٍ سيؤدي var إلى إنشاء متغير محلي ، فلن يبحث "var var" عن سلسلة النطاق حتى يجد المتغير أو يصل إلى النطاق العالمي (عند هذه النقطة سيُنشئه):

// These are both globals
var foo = 1;
bar = 2;

function()
{
    var foo = 1; // Local
    bar = 2;     // Global

    // Execute an anonymous function
    (function()
    {
        var wibble = 1; // Local
        foo = 2; // Inherits from scope above (creating a closure)
        moo = 3; // Global
    }())
}

إذا كنت لا تقوم بمهمة فأنت بحاجة إلى استخدام var :

var x; // Declare x

أود أن أقول أنه من الأفضل استخدام var في معظم الحالات.

تكون المتغيرات المحلية دائمًا أسرع من المتغيرات في النطاق العالمي.

إذا لم تستخدم var لإعلان متغير ، فسيكون المتغير في النطاق العالمي.

لمزيد من المعلومات ، يمكنك البحث عن "نطاق السلسلة JavaScript" في Google.


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

my_var;

لا يمكن العمل في نطاق عالمي أو أي نطاق آخر . يجب أن يكون بقيمة مثل:

my_var = "value";

من ناحية أخرى يمكنك تحديد مثل vaiable.

var my_var;

قيمتها غير undefined (قيمتها غير null ولا تساوي null للاهتمام.).


بدون متغير - متغير عالمي.

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

/* global: varname1, varname2... */

فرق آخر على سبيل المثال

var a = a || [] ; // works 

في حين

a = a || [] ; // a is undefined error.

أعطتChris S مثالا لطيفا يعرض الاختلاف العملي (والخطر) بين var و no var . هنا واحد آخر ، أجد هذا واحد خطير للغاية لأن الفرق هو فقط مرئية في بيئة غير متزامنة حتى يمكن أن تنزلق بسهولة أثناء الاختبار.

كما تتوقع أن تكون مخرجات المقتطف التالية ["text"] :

function var_fun() {
  let array = []
  array.push('text')
  return array
}

console.log(var_fun())

كذلك يفعل المقتطف التالي (لاحظ array المفقودة قبل array ):

function var_fun() {
  array = []
  array.push('text')
  return array
}

console.log(var_fun())

تنفيذ معالجة البيانات بشكل غير متزامن لا يزال ينتج نفس النتيجة مع منفذ واحد:

function var_fun() {
  array = [];
  return new Promise(resolve => resolve()).then(() => {
    array.push('text')
    return array
  })
}

var_fun().then(result => {console.log(result)})

ولكن تتصرف بشكل مختلف مع العديد منها:

function var_fun() {
  array = [];
  return new Promise(resolve => resolve()).then(() => {
    array.push('text')
    return array
  })
}

[1,2,3].forEach(i => {
  var_fun().then(result => {console.log(result)})
})

استخدام دعونا مع ذلك:

function var_fun() {
  let array = [];
  return new Promise(resolve => resolve()).then(() => {
    array.push('text')
    return array
  })
}

[1,2,3].forEach(i => {
  var_fun().then(result => {console.log(result)})
})


كما يحاول أحد أن يتعلم هذا هو كيف أراه. ربما كانت الأمثلة المذكورة أعلاه معقدة بعض الشيء بالنسبة للمبتدئين.

إذا قمت بتشغيل هذا الرمز:

var local = true;
var global = true;


function test(){
  var local = false;
  var global = false;
  console.log(local)
  console.log(global)
}

test();

console.log(local);
console.log(global);

سيتم قراءة الإخراج كـ: false أو false أو true أو true

لأنه يرى أن المتغيرات في الدالة منفصلة عن تلك الموجودة خارجها ، ومن هنا كان مصطلح المتغير المحلي وهذا لأننا استخدمنا var في التخصيص. إذا أزلت var في الدالة ، فتقرأ الآن على النحو التالي:

var local = true;
var global = true;


function test(){
  local = false;
  global = false;
  console.log(local)
  console.log(global)
}

test();

console.log(local);
console.log(global);

المخرجات خاطئة أو خاطئة أو خاطئة أو خاطئة

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


يعتبر استخدام var دائمًا فكرة جيدة لمنع المتغيرات من تشوش النطاق العالمي والمتغيرات من التعارض مع بعضها البعض ، مما يتسبب في الكتابة غير المرغوب فيها.


في ما يلي مثال جيد لكيفية استبعادك من عدم الإعلان عن المتغيرات المحلية باستخدام var :

<script>
one();

function one()
{
    for (i = 0;i < 10;i++)
    {
        two();
        alert(i);
    }
}

function two()
{
    i = 1;
}
</script>

(يتم إعادة ضبط كل مرة في كل تكرار للحلقة ، حيث لا يتم الإعلان عنها محليًا في حلقة for ولكن على مستوى العالم) مما يؤدي في النهاية إلى حلقة لا نهائية


يجب عليك استخدام الكلمة الرئيسية var إلا إذا كنت تنوي إرفاق المتغير بكائن النافذة في المستعرض. في ما يلي رابط يشرح نطاقًا معينًا ومدى اختلاف بين تحديد نطاق الصورة وتحديد النطاق المحلي مع wihtout var keyword.

عندما يتم تعريف المتغيرات دون استخدام كلمة فار ، فإن ما يبدو هو عملية "تعيين" بسيطة.

عندما يتم تعيين القيمة لمتغير في javascript ، يحاول المترجم أولاً العثور على "تعريف متغير" في نفس السياق / النطاق مثل ذلك الواجب. عندما يقوم المترجم بتنفيذ dummyVariable = 20 ، فإنه يبحث عن إعلان dummyVariable عند بداية الدالة. (نظرًا لأن جميع تعريفات المتغير يتم نقلها إلى بداية السياق بواسطة مترجم جافا سكريبت وهذا ما يسمى الرفع)

قد ترغب أيضًا في إلقاء نظرة على javascript





ecmascript-5