Làm cách nào để xóa các đối tượng khỏi mảng kết hợp javascript?


619

Giả sử tôi có mã này:

var myArray = new Object();
myArray["firstname"] = "Bob";
myArray["lastname"] = "Smith";
myArray["age"] = 25;

Bây giờ nếu tôi muốn xóa "họ"? .... thì có tương đương
myArray["lastname"].remove()không?

(Tôi cần phần tử biến mất vì số lượng phần tử là quan trọng và tôi muốn giữ mọi thứ sạch sẽ.)


27
Mẹo: không nhầm lẫn mảng và bản đồ. Một số ngôn ngữ, như php, có một đối tượng cho cả hai. Mặc dù bạn đã sử dụng đúng loại ở đây (đối tượng mới ()) bạn đặt tên cho nó là myArray, nhưng đó chỉ là vấn đề tiêu chuẩn cho một langugage.
Juan Mendes

Đừng quên rằng JavaScript là loại ít hơn và mọi thứ đều là một đối tượng. Xem câu trả lời của Saul dưới đây.
stevek

4
@StephanKristyn - nói chính xác, JS có các loại nhưng theo cách năng độngyếu . Ví dụ, trong khi các biến của nó thực sự là không đánh máy, giá trị của chúng thì không. Đó là phần năng động . Điểm yếu biểu thị rằng các hoạt động giữa các loại giá trị khác nhau không được xác định nghiêm ngặt và dựa vào chuyển đổi phía sau hậu trường; ví dụ "Test" + {};là một câu lệnh JS hoàn toàn hợp lệ.
Saul

Câu trả lời:


1135

Các đối tượng trong JavaScript có thể được coi là mảng kết hợp, khóa ánh xạ (thuộc tính) thành các giá trị.

Để xóa thuộc tính khỏi một đối tượng trong JavaScript, bạn sử dụng deletetoán tử:

const o = { lastName: 'foo' }
o.hasOwnProperty('lastName') // true
delete o['lastName']
o.hasOwnProperty('lastName') // false

Lưu ý rằng khi deleteđược áp dụng cho thuộc tính chỉ mục của an Array, bạn sẽ tạo một mảng dân cư thưa thớt (nghĩa là một mảng có chỉ mục bị thiếu).

Khi làm việc với các phiên bản của Array, nếu bạn không muốn tạo một mảng dân cư thưa thớt - và bạn thường không - thì bạn nên sử dụng Array#splicehoặc Array#pop.

Lưu ý rằng deletetoán tử trong JavaScript không trực tiếp giải phóng bộ nhớ. Mục đích của nó là để loại bỏ các thuộc tính từ các đối tượng. Tất nhiên, nếu một thuộc tính bị xóa giữ tham chiếu duy nhất còn lại cho một đối tượng o, thì sau đó osẽ là rác được thu thập theo cách thông thường.

Sử dụng deletetoán tử có thể ảnh hưởng đến khả năng tối ưu hóa của công cụ JavaScript .


18
Điều này sẽ gây ra vấn đề nếu được sử dụng trên một đối tượng Array để loại bỏ một phần tử hiện có, ví dụ delete myArray[0]. Xem stackoverflow.com/a/9973592/426379Xóa các phần tử mảng
Saul

4
Những vấn đề sẽ được gây ra?
Gottox

26
@Gottox - lengthThuộc tính của một đối tượng Array không thay đổi.
Saul

12
@Saul: sẽ có vấn đề nếu myArraythực sự được sử dụng như một mảng - nhưng nó không phải ( myArraylà tên không may), nó là một đối tượng. Vì vậy, trong trường hợp deletenày là OK. Lưu ý rằng ngay cả khi nó được tạo new Array()và sử dụng như mảng kết hợp thì nó vẫn ổn. Cảnh báo của bạn vẫn là điều cần lưu ý nếu một người đang sử dụng mảng thực sự.
johndodo

2
@johndodo - Đúng. Đó là lý do tại sao tôi bắt đầu nhận xét ban đầu của mình với Điều này sẽ gây ra sự cố nếu được sử dụng trên một đối tượng Array . Tuy nhiên tôi thích một cách tiếp cận thực hiện chính xác trong mọi trường hợp, xem câu trả lời của tôi dưới đây.
Saul

79

Tất cả các đối tượng trong JavaScript được triển khai dưới dạng hashtables / mảng kết hợp. Vì vậy, sau đây là tương đương:

alert(myObj["SomeProperty"]);
alert(myObj.SomeProperty);

Và, như đã chỉ ra, bạn "xóa" một thuộc tính khỏi một đối tượng thông qua deletetừ khóa, mà bạn có thể sử dụng theo hai cách:

delete myObj["SomeProperty"];
delete myObj.SomeProperty;

Hy vọng thông tin thêm sẽ giúp ...


10
cần lưu ý rằng ký hiệu dấu chấm không hoạt động nếu thuộc tính không phải là một thuật ngữ đơn giản. tức là myObj['some;property']hoạt động, nhưng myObj.some;propertysẽ không (vì lý do rõ ràng). Ngoài ra, có thể không rõ ràng rằng bạn có thể sử dụng một biến trong ký hiệu dấu ngoặc, tức làvar x = 'SomeProperty'; alert(myObj[x])
Kip

2
"Tất cả các đối tượng trong JavaScript được triển khai dưới dạng hashtables / mảng kết hợp." - false. V8 thích lưu trữ một đối tượng dưới dạng một lớp ẩn + các trường được đóng gói dày đặc. Chỉ khi bạn làm những thứ kỳ lạ với họ (chẳng hạn như loại bỏ các trường), nó sẽ từ bỏ và sử dụng bản đồ băm phía sau hậu trường.
John Dvorak

4
@JanDvorak - này, bạn có nhận ra khi câu trả lời này ban đầu được viết không? Mô tả đó đã và vẫn đủ cho hầu hết các mục đích. Điều đó nói rằng, tôi hiểu là tẻ nhạt. :)
Jason Bunting

41

Không có câu trả lời nào trước đây đề cập đến thực tế là Javascript không có mảng kết hợp để bắt đầu - không có arrayloại nào như vậy, xem typeof.

Javascript có gì, là các thể hiện đối tượng có thuộc tính động. Khi các thuộc tính bị nhầm lẫn với các phần tử của một đối tượng Array thì Bad Things ™ bị ràng buộc xảy ra:

Vấn đề

var elements = new Array()

elements.push(document.getElementsByTagName("head")[0])
elements.push(document.getElementsByTagName("title")[0])
elements["prop"] = document.getElementsByTagName("body")[0]

console.log("number of elements: ", elements.length)   // returns 2
delete elements[1]
console.log("number of elements: ", elements.length)   // returns 2 (?!)

for (var i = 0; i < elements.length; i++)
{
   // uh-oh... throws a TypeError when i == 1
   elements[i].onmouseover = function () { window.alert("Over It.")}
   console.log("success at index: ", i)
}

Giải pháp

Để có chức năng loại bỏ phổ quát không làm bạn thất vọng, hãy sử dụng:

Object.prototype.removeItem = function (key) {
   if (!this.hasOwnProperty(key))
      return
   if (isNaN(parseInt(key)) || !(this instanceof Array))
      delete this[key]
   else
      this.splice(key, 1)
};

//
// Code sample.
//
var elements = new Array()

elements.push(document.getElementsByTagName("head")[0])
elements.push(document.getElementsByTagName("title")[0])
elements["prop"] = document.getElementsByTagName("body")[0]

console.log(elements.length)                        // returns 2
elements.removeItem("prop")
elements.removeItem(0)
console.log(elements.hasOwnProperty("prop"))        // returns false as it should
console.log(elements.length)                        // returns 1 as it should

8
Giải pháp này có hai vấn đề: nó che giấu thực tế là các mảng và đối tượng là những con thú hoàn toàn khác nhau trong JS (bạn biết điều đó, nhưng rõ ràng OP không) và nó sử dụng các nguyên mẫu. OP sẽ tốt hơn nếu anh ta biết về mảng và đối tượng (và sẽ đặt tên cho các biến của mình theo đó) - cố gắng che giấu sự khác biệt giữa hai điều này sẽ chỉ khiến anh ta gặp nhiều rắc rối hơn. IMHO tất nhiên.
johndodo

1
@johndodo - tất cả các Arrays trong JS đều là đối tượng, hãy thử typeof new Array();hoặc typeof []để xác minh. Arraychỉ đơn giản là một loại vật thể nhất định và hoàn toàn không phải là một "con thú khác". Trong JS, các đối tượng được phân biệt bằng tên hàm tạo và chuỗi nguyên mẫu của chúng, xem lập trình dựa trên Nguyên mẫu .
Saul

9
Bạn đang bị mất điểm. Tôi biết rằng mảng cũng là đối tượng, nhưng điều đó không có nghĩa là khôn ngoan khi sử dụng chúng như vậy. Lập trình viên nên quyết định xem anh ta muốn sử dụng một cái gì đó như mảng (với đẩy, pop, [], ...) hoặc làm đối tượng / "mảng kết hợp". Trộn và kết hợp không phải là một công thức tốt, chính xác là do các vấn đề mà giải pháp của bạn đang cố gắng che giấu. Nếu bạn quyết định trước nên sử dụng mẫu thiết kế nào (mảng hoặc đối tượng) thì sẽ không có vấn đề nào như vậy.
johndodo

7
@johndodo - Bạn đang nói về vấn đề gì cụ thể? Mục đích của mã trên là để nhấn mạnh deletetoán tử thiếu có liên quan đến Arrayviệc cung cấp một hàm đa hình đơn giản.
Saul

1
deletekhông có sự thiếu hụt deleteđược thiết kế để loại bỏ các thuộc tính. Đó là nó. Áp dụng toán tử xóa vào một chỉ mục của một mảng sẽ loại bỏ chỉ mục đó. Cần gì hơn nó làm gì? Bạn còn lại với một mảng thưa thớt, đó là một tính năng của ngôn ngữ. Nếu bạn không muốn một mảng thưa thớt, đừng xóa chỉ mục: use splicehoặc pop.
Ben Aston

35

Điều đó chỉ loại bỏ xóa đối tượng nhưng vẫn giữ nguyên chiều dài mảng.

Để loại bỏ bạn cần làm một cái gì đó như:

array.splice(index, 1);

11
Thật vậy, nhưng trong trường hợp này, một mảng không được sử dụng, chỉ là một đối tượng cũ đơn giản, do đó nó không có phương thức độ dài hoặc mối nối.
MooGoo

2
@Andreaa Panagiotidis Ngoại trừ khi chúng ta không nói về Mảng, trong trường hợp đó, nó sai 100% thời gian
Drenai

17

Trong khi câu trả lời được chấp nhận là chính xác, nó thiếu phần giải thích tại sao nó hoạt động.

Trước hết, mã của bạn phải phản ánh thực tế rằng đây KHÔNG phải là một mảng:

var myObject = new Object();
myObject["firstname"] = "Bob";
myObject["lastname"] = "Smith";
myObject["age"] = 25;

Lưu ý rằng tất cả các đối tượng (bao gồm cả Arrays) có thể được sử dụng theo cách này. Tuy nhiên, đừng mong đợi các hàm mảng JS tiêu chuẩn (pop, đẩy, ...) hoạt động trên các đối tượng!

Như đã nói trong câu trả lời được chấp nhận, sau đó bạn có thể sử dụng deleteđể xóa các mục khỏi đối tượng:

delete myObject["lastname"]

Bạn nên quyết định tuyến đường nào bạn muốn đi - sử dụng các đối tượng (mảng kết hợp / từ điển) hoặc sử dụng mảng (bản đồ). Không bao giờ trộn lẫn hai người họ.


6
Câu trả lời rất hay. Tôi chỉ khuyên mọi người đọc điều này rằng Mảng trong javascript không nên được trừu tượng hóa thành 'bản đồ', mà là 'danh sách'. Đó là bởi vì bạn không nên cố gắng kiểm soát chỉ mục của các yếu tố khi sử dụng mảng. Nếu bạn thử ... tốt, đừng, đừng: D
Rodolfo42

6

Sử dụng phương thức spliceđể loại bỏ hoàn toàn mục khỏi một mảng đối tượng:

Object.prototype.removeItem = function (key, value) {
    if (value == undefined)
        return;

    for (var i in this) {
        if (this[i][key] == value) {
            this.splice(i, 1);
        }
    }
};

var collection = [
    { id: "5f299a5d-7793-47be-a827-bca227dbef95", title: "one" },
    { id: "87353080-8f49-46b9-9281-162a41ddb8df", title: "two" },
    { id: "a1af832c-9028-4690-9793-d623ecc75a95", title: "three" }
];

collection.removeItem("id", "87353080-8f49-46b9-9281-162a41ddb8df");

1
đây là một giải pháp chung chung hơn, có thể được thêm vào tệp js của bạn và phương thức sẽ có sẵn cho tất cả các mảng, không chỉ một mảng.
Hussain

6

Như các câu trả lời khác đã lưu ý, những gì bạn đang sử dụng không phải là một mảng Javascript, mà là một đối tượng Javascript, hoạt động gần giống như một mảng kết hợp trong các ngôn ngữ khác ngoại trừ tất cả các khóa được chuyển đổi thành chuỗi. Bản đồ mới lưu trữ các khóa như loại ban đầu của chúng.

Nếu bạn có một mảng và không phải là một đối tượng, bạn có thể sử dụng mảng đó hàm .filter , để trả về một mảng mới mà không cần xóa mục bạn muốn:

var myArray = ['Bob', 'Smith', 25];
myArray = myArray.filter(function(item) {
    return item !== 'Smith';
});

Nếu bạn có trình duyệt cũ hơn và jQuery, jQuery có một $.grepphương thức hoạt động tương tự:

myArray = $.grep(myArray, function(item) {
    return item !== 'Smith';
});

giải thích hoàn hảo. Tôi đã sử dụng bộ lọc để đạt được kết quả mong muốn. Bạn có thể giải thích làm thế nào mục trả về hoạt động để loại bỏ đối tượng khỏi mảng. Tôi giả sử nó trả về mảng miễn là nó không bao gồm chuỗi bạn đưa vào.
Edward


5

Bạn đang sử dụng Object, bạn không có một mảng kết hợp để bắt đầu. Với một mảng kết hợp, việc thêm và xóa các mục sẽ diễn ra như sau:

    Array.prototype.contains = function(obj) 
    {
        var i = this.length;
        while (i--) 
        {
            if (this[i] === obj) 
            {
                return true;
            }
        }
        return false;
    }


    Array.prototype.add = function(key, value) 
    {
        if(this.contains(key))
            this[key] = value;
        else
        {
            this.push(key);
            this[key] = value;
        }
    }


    Array.prototype.remove = function(key) 
    {
        for(var i = 0; i < this.length; ++i)
        {
            if(this[i] == key)
            {
                this.splice(i, 1);
                return;
            }
        }
    }



    // Read a page's GET URL variables and return them as an associative array.
    function getUrlVars()
    {
        var vars = [], hash;
        var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');

        for(var i = 0; i < hashes.length; i++)
        {
            hash = hashes[i].split('=');
            vars.push(hash[0]);
            vars[hash[0]] = hash[1];
        }

        return vars;
    }



    function ForwardAndHideVariables() {
        var dictParameters = getUrlVars();

        dictParameters.add("mno", "pqr");
        dictParameters.add("mno", "stfu");

        dictParameters.remove("mno");



        for(var i = 0; i < dictParameters.length; i++)
        {
            var key = dictParameters[i];
            var value = dictParameters[key];
            alert(key + "=" + value);
        }
        // And now forward with HTTP-POST
        aa_post_to_url("Default.aspx", dictParameters);
    }


    function aa_post_to_url(path, params, method) {
        method = method || "post";

        var form = document.createElement("form");

        //move the submit function to another variable
        //so that it doesn't get written over if a parameter name is 'submit'
        form._submit_function_ = form.submit;

        form.setAttribute("method", method);
        form.setAttribute("action", path);

        for(var i = 0; i < params.length; i++)
        {
            var key = params[i];

            var hiddenField = document.createElement("input");
            hiddenField.setAttribute("type", "hidden");
            hiddenField.setAttribute("name", key);
            hiddenField.setAttribute("value", params[key]);

            form.appendChild(hiddenField);
        }

        document.body.appendChild(form);
        form._submit_function_(); //call the renamed function
    }

4

Bạn có thể xóa một mục khỏi bản đồ của mình bằng cách gán rõ ràng cho mục 'không xác định'. Như trong trường hợp của bạn:

myArray ["lastname"] = không xác định;


Điều này có thể hữu ích trong trường hợp người ta không chắc liệu khóa có tồn tại trong từ điển hay không, nhưng muốn vệ sinh nó trong trường hợp có. Sửa lỗi cho tôi nếu tôi sai Amytis.
Hassan Baig

3

Nếu vì lý do nào đó, phím xóa không hoạt động (như nó không hoạt động với tôi)

Bạn có thể ghép nó ra và sau đó lọc các giá trị không xác định

// to cut out one element via arr.splice(indexToRemove, numberToRemove);
array.splice(key, 1)
array.filter(function(n){return n});

Đừng thử và xâu chuỗi chúng vì mối nối trả về các phần tử bị loại bỏ;


3

Chúng ta có thể sử dụng nó như là một chức năng quá. Angular ném một số lỗi nếu được sử dụng như một nguyên mẫu. Cảm ơn @HarpyWar. Nó giúp tôi giải quyết một vấn đề.

var removeItem = function (object, key, value) {
    if (value == undefined)
        return;

    for (var i in object) {
        if (object[i][key] == value) {
            object.splice(i, 1);
        }
    }
};

var collection = [
    { id: "5f299a5d-7793-47be-a827-bca227dbef95", title: "one" },
    { id: "87353080-8f49-46b9-9281-162a41ddb8df", title: "two" },
    { id: "a1af832c-9028-4690-9793-d623ecc75a95", title: "three" }
];

removeItem(collection, "id", "87353080-8f49-46b9-9281-162a41ddb8df");

2

Nó rất thẳng về phía trước nếu bạn có sự phụ thuộc underscore.js trong dự án của bạn -

_.omit(myArray, "lastname")

1

Bằng cách sử dụng "delete"từ khóa, nó sẽ xóa phần tử mảng khỏi mảng trong javascript.

Ví dụ,

Hãy xem xét các tuyên bố sau.

var arrayElementToDelete = new Object();

arrayElementToDelete["id"]           = "XERTYB00G1"; 
arrayElementToDelete["first_name"]   = "Employee_one";
arrayElementToDelete["status"]       = "Active"; 

delete arrayElementToDelete["status"];

Dòng cuối cùng của mã sẽ loại bỏ phần tử mảng là khóa "trạng thái" khỏi mảng.


0
var myArray = newmyArray = new Object(); 
myArray["firstname"] = "Bob";
myArray["lastname"] = "Smith";
myArray["age"] = 25;

var s = JSON.stringify(myArray);

s.replace(/"lastname[^,}]+,/g,'');
newmyArray = JSON.parse(p);

Không lặp / lặp chúng ta sẽ có kết quả tương tự


0

Đối với "Mảng":

Nếu bạn biết chỉ số:

array.splice(index, 1);

Nếu bạn biết giá trị:

function removeItem(array, value) {
    var index = array.indexOf(value);
    if (index > -1) {
        array.splice(index, 1);
    }
    return array;
}

Câu trả lời được đánh giá cao nhất cho deletehoạt động tốt trong trường hợp các đối tượng nhưng không phải cho các mảng thực. Nếu tôi sử dụng deletenó sẽ loại bỏ các phần tử khỏi các vòng lặp nhưng giữ nguyên phần tử nhưempty và độ dài của mảng sẽ không thay đổi. Đây có thể là một vấn đề trong một số tình huống.

Ví dụ: nếu tôi thực hiện myArray.toString () trên myArray sau khi xóa thông qua deletenó sẽ tạo mục nhập trống tức là ,,


0

Phương pháp làm việc duy nhất cho tôi:

function removeItem (array, value) {
    var i = 0;
    while (i < array.length) {
        if(array[i] === value) {
            array.splice(i, 1);
        } else {
            ++i;
        }
    }
    return array;
}

sử dụng:

var new = removeItem( ["apple","banana", "orange"],  "apple");
// ---> ["banana", "orange"]

Tại sao không sử dụng bộ lọc thay thế? đây là trường hợp sử dụng hoàn hảo cho bộ lọc
Code Maniac
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.