على - كيف أقوم بتفريغ مصفوفة في JavaScript؟




شرح جافا سكريبت (12)

هل هناك طريقة لتفريغ مصفوفة وإذا كان الأمر كذلك ، ربما مع .remove() ؟

على سبيل المثال،

A = [1,2,3,4];

كيف يمكنني تفريغ ذلك؟


أنا مندهش لا أحد اقترح هذا حتى الآن:

let xs = [1,2,3,4];
for (let i in xs)
    delete xs[i];

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

xs
=> Array [ <4 empty slots> ]

[...xs]
=> Array [ undefined, undefined, undefined, undefined ]

xs.length
=> 4

xs[0]
=> ReferenceError: reference to undefined property xs[0]

يمكنك إنتاج صفيف مكافئ مع [,,,,] أو Array(4)


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

A.length = 0;

إذا كنت تستخدم الثوابت فلا خيار أمامك:

const numbers = [1, 2, 3]

لا يمكنك إعادة تعيين:

numbers = []

يمكنك فقط اقتطاع:

numbers.length = 0

إذا كنت مهتمًا بتخصيص الذاكرة ، فيمكنك مقارنة كل طريقة باستخدام شيء مثل jsfiddle بالتزامن مع علامة التبويب الزمني لأدوات chrome dev. ستحتاج إلى استخدام رمز سلة المهملات في الجزء السفلي لفرض مجموعة بيانات المهملة بعد "مسح" الصفيف. يجب أن يمنحك هذا إجابة أكثر تحديدًا للمتصفح الذي تختاره. هناك الكثير من الإجابات هنا قديمة ولن أعتمد عليها ولكن بدلاً من اختبارها في الإجابة على @ tanguy_k أعلاه.

(للمقدمة إلى علامة التبويب المذكورة أعلاه يمكنك التحقق من here )

يجبرني على نسخ jsfiddle حتى هنا هو:

<html>
<script>
var size = 1000*100
window.onload = function() {
  document.getElementById("quantifier").value = size
}

function scaffold()
{
  console.log("processing Scaffold...");
  a = new Array
}
function start()
{
  size = document.getElementById("quantifier").value
  console.log("Starting... quantifier is " + size);
  console.log("starting test")
  for (i=0; i<size; i++){
    a[i]="something"
  }
  console.log("done...")
}

function tearDown()
{
  console.log("processing teardown");
  a.length=0
}

</script>
<body>
    <span style="color:green;">Quantifier:</span>
    <input id="quantifier" style="color:green;" type="text"></input>
    <button onclick="scaffold()">Scaffold</button>
    <button onclick="start()">Start</button>
    <button onclick="tearDown()">Clean</button>
    <br/>
</body>
</html>

ويجب أن تأخذ ملاحظة أنه قد يعتمد على نوع عناصر الصفيف ، حيث يدير javascript السلاسل بشكل مختلف عن الأنواع البدائية الأخرى ، ناهيك عن صفائف الكائنات. قد يؤثر النوع على ما يحدث.


الأجوبة التي لا تقل عن 2739 من الأصوات المقبولة حتى الآن هي مضللة وغير صحيحة.

السؤال هو: "كيف تفريغ صفيفك الحالي؟" مثلا ل A = [1,2,3,4] .

  1. القول " A = [] هو الجواب" هو جاهل وغير صحيح على الإطلاق. [] == [] غير صحيح .

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

لنفترض أن والدتك تطلب منك تفريغ سلة المهملات.

  • لا تجلب واحدة جديدة كما لو كنت قد فعلت ما طلب منك.
  • بدلاً من ذلك ، يمكنك إفراغ سلة المهملات.
  • أنت لا تحل محل واحد معبأ مع علبة فارغة جديدة ، وأنت لا تأخذ التسمية "A" من العلبة المعبأة والتشبث بها الجديدة كما في A = [1,2,3,4]; A = []; A = [1,2,3,4]; A = [];

إفراغ كائن المصفوفة هو أسهل شيء على الإطلاق:

A.length = 0;

بهذه الطريقة ، لا يمكن للعلامة "A" تحت عنوان "A" أن تكون فارغة فحسب ، بل أيضًا نظيفة مثل الجديدة!

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

    while(A.length > 0) {
        A.pop();
    }
    
  2. ولا تضع يدك اليسرى أسفل سلة المهملات ، فضعها في يمينك في الأعلى لتتمكن من سحب محتواها كما هو الحال في:

    A.splice(0, A.length);
    

لا ، لقد طُلب منك تفريغها:

A.length = 0;

هذا هو الرمز الوحيد الذي يقوم بإفراغ محتويات صفيف JavaScript محدد بشكل صحيح.



طرق لمسح صف A موجود:

طريقة 1

(هذه كانت إجابتي الأصلية على السؤال)

A = [];

سيقوم هذا الرمز بتعيين المتغير A إلى صفيف فارغ جديد. هذا مثالي إذا لم يكن لديك إشارات إلى الصفيف الأصلي A أي مكان آخر لأن هذا في الواقع ينشئ صفيف جديد (فارغ). يجب أن تكون حذراً مع هذه الطريقة لأنه إذا قمت بالإشارة إلى هذا الصفيف من متغير آخر أو خاصية أخرى ، فسيظل المصفوفة الأصلية بدون تغيير. استخدم هذا فقط إذا قمت فقط بالرجوع إلى الصفيف من خلال متغيره الأصلي A

هذا هو أيضا الحل الأسرع.

يعرض نموذج التعليمات البرمجية هذا المشكلة التي قد تواجهها عند استخدام هذه الطريقة:

var arr1 = ['a','b','c','d','e','f'];
var arr2 = arr1;  // Reference arr1 by another variable 
arr1 = [];
console.log(arr2); // Output ['a','b','c','d','e','f']

الطريقة الثانية (كما suggested Matthew Crumley )

A.length = 0

سيؤدي هذا إلى مسح الصفيف الموجود عن طريق تعيين طوله إلى 0. وقد جادل البعض بأن هذا قد لا يعمل في جميع تطبيقات جافا سكريبت ، ولكن تبين أن الأمر ليس كذلك. كما أنه يعمل عند استخدام "الوضع المقيد" في ECMAScript 5 لأن خاصية الطول لصفيف هي خاصية القراءة / الكتابة.

الطريقة الثالثة (كما suggested Anthony )

A.splice(0,A.length)

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

الطريقة الرابعة (كما هو suggested بواسطة tanguy_k )

while(A.length > 0) {
    A.pop();
}

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

أداء

من بين جميع أساليب مسح صفيف موجود ، تكون الطريقتان 2 و 3 متشابهة جدًا في الأداء وهي أسرع كثيرًا من الطريقة 4. انظر هذا benchmark .

كما أشار Diadistis في answer أدناه ، فإن المعايير الأصلية التي استخدمت لتحديد أداء الطرق الأربعة المذكورة أعلاه كانت معيبة. قام المعيار الأصلي بإعادة استخدام المصفوفة التي تم مسحها ، لذلك كان التكرار الثاني يقوم بمسح صفيف فارغ بالفعل.

يعمل المعيار التالي على إصلاح هذا الخطأ: benchmark . يظهر بوضوح أن الطرق # 2 (خاصية الطول) و # 3 (لصق) هي الأسرع (لا طريقة العد # 1 التي لا تغير الصفيف الأصلي).

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


هناك الكثير من الارتباك والتضليل فيما يتعلق بالوقت ، أداء البوب ​​/ التحول في كل من الإجابات والتعليقات. الحل أثناء / البوب ​​(كما هو متوقع) أسوأ أداء . ما يحدث في الواقع هو أن الإعداد يعمل مرة واحدة فقط لكل عينة تقوم بتشغيل المقتطف في حلقة. على سبيل المثال:

var arr = [];

for (var i = 0; i < 100; i++) { 
    arr.push(Math.random()); 
}

for (var j = 0; j < 1000; j++) {
    while (arr.length > 0) {
        arr.pop(); // this executes 100 times, not 100000
    }
}

لقد قمت بإنشاء اختبار جديد يعمل بشكل صحيح:

http://jsperf.com/empty-javascript-array-redux

تحذير: حتى في هذا الإصدار من الاختبار ، لا يمكنك رؤية الفرق الحقيقي لأن استنساخ الصفيف يستغرق معظم وقت الاختبار. لا يزال يظهر أن splice هو أسرع طريقة لمسح الصفيف (وليس أخذ [] في الاعتبار لأنه في حين أنه الأسرع فإنه لا يتم في الواقع مسح الصفيف الموجود.


يمكنك بسهولة إنشاء دالة للقيام بذلك نيابة عنك أو تغيير الطول أو حتى إضافته إلى صفيف أصلي كإزالة remove() وظيفة لإعادة الاستخدام.

تخيل أن لديك هذه المجموعة:

var arr = [1, 2, 3, 4, 5]; //the array

حسنًا ، ما عليك سوى تشغيل هذا:

arr.length = 0; //change the length

والنتيجة هي:

[] //result

طريقة سهلة لتفريغ مجموعة ...

أيضا باستخدام حلقة ليست ضرورية ولكن مجرد طريقة أخرى للقيام بذلك:

/* could be arr.pop() or arr.splice(0)
don't need to return as main array get changed */

function remove(arr) {
  while(arr.length) {
    arr.shift(); 
  }
}

هناك أيضًا طريقة صعبة يمكنك التفكير فيها ، على سبيل المثال شيء من هذا القبيل:

arr.splice(0, arr.length); //[]

إذا كان لدى arr 5 عناصر ، فسيؤدي ذلك إلى لصق 5 عناصر من 0 ، مما يعني أن أي شيء سيبقى في الصفيف.

أيضًا طرق أخرى مثل إعادة تعيين الصفيف على سبيل المثال:

arr = []; //[]

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

كما قلت في المقام الأول ، يمكنك أيضًا إنشاء نموذج الإزالة () باعتباره الإجابة على سؤالك. يمكنك ببساطة اختيار إحدى الطرق المذكورة أعلاه ووضع نموذج لها على كائن الصفيف في JavaScript ، وهو ما يلي:

Array.prototype.remove = Array.prototype.remove || function() {
  this.splice(0, this.length);
};

ويمكنك ببساطة تسمية مثل هذا لتفريغ أي مصفوفة في تطبيق جافا سكريبت الخاص بك:

arr.remove(); //[]

لإفراغ موقع ذاكرة الحالي لصفيف استخدام: 'myArray.length = 0'أو'myArray.pop() UN-till its length is 0'

  • length: يمكنك تعيين خاصية الطول لاقتطاع مصفوفة في أي وقت. عند توسيع صفيف عن طريق تغيير الخاصية الطول ، يزيد عدد العناصر الفعلية.
  • pop(): تقوم طريقة pop بإزالة العنصر الأخير من صفيف وإرجاع ترجع القيمة التي تمت إزالتها.
  • shift(): تقوم طريقة shift بإزالة العنصر الموجود في فهرس الصفر وفصل القيم عند الفهارس المتعاقبة لأسفل ، ثم إرجاع القيمة التي تمت إزالتها.

مثال:

var arr = ['77'];
arr.length = 20;
console.log("Increasing : ", arr); // (20) ["77", empty × 19]
arr.length = 12;
console.log("Truncating : ", arr); // (12) ["77", empty × 11]

var mainArr = new Array();
mainArr = ['1', '2', '3', '4'];

var refArr = mainArr;
console.log('Current', mainArr, 'Refered', refArr);

refArr.length = 3;
console.log('Length: ~ Current', mainArr, 'Refered', refArr);

mainArr.push('0');
console.log('Push to the End of Current Array Memory Location \n~ Current', mainArr, 'Refered', refArr);

mainArr.poptill_length(0);
console.log('Empty Array \n~ Current', mainArr, 'Refered', refArr);

Array.prototype.poptill_length = function (e) {
  while (this.length) {
    if( this.length == e ) break;

    console.log('removed last element:', this.pop());
  }
};
  • Array إنشاء صفيف مع موقع ذاكرة جديد باستخدام Array constructorأو array literal.

    mainArr = []; // a new empty array is addressed to mainArr.
    
    var arr = new Array('10'); // Array constructor
    arr.unshift('1'); // add to the front
    arr.push('15'); // add to the end
    console.log("After Adding : ", arr); // ["1", "10", "15"]
    
    arr.pop(); // remove from the end
    arr.shift(); // remove from the front
    console.log("After Removing : ", arr); // ["10"]
    
    var arrLit = ['14', '17'];
    console.log("array literal « ", indexedItem( arrLit ) ); // {0,14}{1,17}
    
    function indexedItem( arr ) {
        var indexedStr = "";
        arr.forEach(function(item, index, array) {
            indexedStr += "{"+index+","+item+"}";
            console.log(item, index);
        });
        return indexedStr;
    }
    
  • slice() : باستخدام وظيفة الشريحة نحصل على نسخة ضحلة من العناصر من المصفوفة الأصلية ، مع عنوان ذاكرة جديد ، بحيث لن يؤثر أي تعديل على cloneArr على مصفوفة حقيقية |

    var shallowCopy = mainArr.slice(); // this is how to make a copy
    
    var cloneArr = mainArr.slice(0, 3); 
    console.log('Main', mainArr, '\tCloned', cloneArr);
    
    cloneArr.length = 0; // Clears current memory location of an array.
    console.log('Main', mainArr, '\tCloned', cloneArr);
    

هنا أسرع تنفيذ العمل مع الحفاظ على نفس المجموعة ("mutable"):

Array.prototype.clear = function() {
  while (this.length) {
    this.pop();
  }
};

تحدد Map FYI clear() بحيث يبدو منطقيًا أن يكون لديك clear() لـ Array أيضًا.

أو كخليط Underscore.js :

_.mixin({
  clearArray: function(array) {
    while (array.length) {
      array.pop();
    }
  }
});

أو وظيفة بسيطة:

function clearArray(array) {
  while (array.length) {
    array.pop();
  }
}

إصدار TypeScript :

function clearArray<T>(array: T[]) {
  while (array.length) {
    array.pop();
  }
}

لمعلوماتك لا يمكن تبسيطها while (array.pop()) : ستفشل الاختبارات.

والاختبارات التي تتوافق معها:

describe('Array', () => {
  it('should clear the array', () => {
    let array = [1, 2, 3, 4, 5];
    array.clear();
    expect(array.length).toEqual(0);
    expect(array[0]).toEqual(undefined);
    expect(array[4]).toEqual(undefined);

    // Even with undefined or null inside
    array = [1, undefined, 3, null, 5];
    array.clear();
    expect(array.length).toEqual(0);
    expect(array[0]).toEqual(undefined);
    expect(array[4]).toEqual(undefined);
  });
});

هنا jsPerf المحدثة: http://jsperf.com/array-destroy/32 http://jsperf.com/array-destroy/152


استخدم أدناه إذا كنت بحاجة إلى إفراغ Angular 2+ FormArray.

public emptyFormArray(formArray:FormArray) {
    for (let i = formArray.controls.length - 1; i >= 0; i--) {
        formArray.removeAt(i);
    }
}






arrays