a

Câu hỏi Làm cách nào để xóa thuộc tính khỏi đối tượng JavaScript?


Giả sử tôi tạo một đối tượng như sau:

var myObject = {
    "ircEvent": "PRIVMSG",
    "method": "newURI",
    "regex": "^http://.*"
};

Cách tốt nhất để xóa thuộc tính là gì regex để kết thúc với mới myObject như sau?

var myObject = {
    "ircEvent": "PRIVMSG",
    "method": "newURI"
};

4910
2017-10-16 10:57


gốc


Tìm ở đây điểm chuẩn so sánh "xóa" so với "không xác định" so với "null" jsben.ch/#/BWMiw - EscapeNetscape
developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… - titusfx


Các câu trả lời:


Như thế này:

delete myObject.regex;
// or,
delete myObject['regex'];
// or,
var prop = "regex";
delete myObject[prop];

Bản giới thiệu

var myObject = {
    "ircEvent": "PRIVMSG",
    "method": "newURI",
    "regex": "^http://.*"
};
delete myObject.regex;

console.log(myObject);

Đối với bất kỳ ai quan tâm đến việc đọc thêm về nó, người dùng Stack Overflow kangax đã viết một bài đăng blog cực kỳ chuyên sâu về delete tuyên bố trên blog của họ, Hiểu xóa. Nó là rất khuyến khích.


6839
2017-10-16 10:58



Kiểm tra, nó cũng làm việc với "xóa myJSONObject ['regex'];" Xem: developer.mozilla.org/en/Core_JavaScript_1.5_Reference/… - johnstok
Một kết quả của một trong những quan sát tại liên kết "hiểu xóa" ở trên, là vì bạn không nhất thiết có thể xóa biến, nhưng chỉ các thuộc tính đối tượng, do đó bạn không thể xóa thuộc tính đối tượng "bằng tham chiếu" - var value = obj [ 'prop']; giá trị xóa // không hoạt động - George Jempty
Vì vậy, nó không thực sự xóa nó? Nó chỉ trở thành không xác định, nhưng chìa khóa vẫn còn tồn tại? Tui bỏ lỡ điều gì vậy? - Doug Molineux
@Pete không, nó loại bỏ nó. Được: var x = {a : 'A', b : 'B'}; So sánh: delete x.a; typeof x.a; /* "undefined" */ x.hasOwnProperty('a'); /* false */ đến x.b = undefined; typeof x.b; /* "undefined" */; x.hasOwnProperty('b'); /* true */ - nickf
@ChristopherPfohl hoạt động cho tôi. Như tôi đã nói, nó thực sự khá sâu, nên có một chút khó khăn để tóm tắt. Câu trả lời cơ bản trong câu trả lời ở trên là đủ cho hầu hết các trường hợp, blog đi sâu vào một số trường hợp cạnh và lý do những trường hợp đó tồn tại. - nickf


Nhà điều hành delete bất ngờ chậm!

Nhìn vào điểm chuẩn.

Xóa là cách duy nhất để loại bỏ các thuộc tính của đối tượng mà không có bất kỳ dư thừa nào, nhưng nó hoạt động ~ 100 lần chậm hơn, so với cài đặt "thay thế" của nó object[key] = undefined.

Lựa chọn thay thế này không phải là câu trả lời đúng cho câu hỏi này! Nhưng, nếu bạn sử dụng nó cẩn thận, bạn có thể tăng tốc đáng kể một số thuật toán. Nếu bạn đang sử dụng delete trong các vòng lặp và bạn gặp vấn đề với hiệu năng, hãy đọc giải thích chi tiết.

Khi nào nên sử dụng delete và khi đặt giá trị thành undefined ?

Một đối tượng có thể được xem như một tập hợp các cặp khóa-giá trị. Cái mà tôi gọi là 'giá trị' là một nguyên thủy hoặc một tham chiếu đến đối tượng khác, được kết nối với 'khóa' đó.

Sử dụng delete, khi bạn đang chuyển đối tượng kết quả tới mã mà bạn không có quyền kiểm soát (hoặc khi bạn không chắc chắn về nhóm của bạn hoặc chính bạn).

xóa khóa khỏi hashmap.

 var obj = {
     field: 1     
 };
 delete obj.field;

Sử dụng cài đặt cho undefined, khi bạn quan tâm đến hiệu suất. Nó có thể tăng cường nghiêm trọng cho mã của bạn.

Các chính vẫn còn trên vị trí của nó trong hashmap, chỉ giá trị được thay thế bằng undefined. Hiểu, rằng for..in vòng lặp sẽ vẫn lặp qua khóa đó.

 var obj = {
     field: 1     
 };
 obj.field = undefined;

Sử dụng phương pháp này, không phải tất cả cách xác định sự tồn tại của tài sản sẽ hoạt động như mong đợi.

Tuy nhiên, mã này:

object.field === undefined

sẽ hoạt động tương đương cho cả hai phương pháp.

Kiểm tra

Tóm lại, sự khác biệt là tất cả về cách xác định sự tồn tại của tài sản, và về for..in vòng lặp.

 console.log('* -> "Takes prototype inheritance into consideration, that means it lookups all over prototype chain too."');

 console.log(obj.field === undefined, 'obj.field === undefined', 'You get "undefined" value when querying for "field" in object-hashmap. *');

 console.log(obj["field"] === undefined, 'obj["field"] === undefined', 'Just another way to query (equivalent). *');

 console.log(typeof obj.field === "undefined", 'typeof obj.field === "undefined"', 'Get the value attached to "field" key, and check it\'s type is "undefined". *');

 console.log("field" in obj, '"field" in obj', 'This statement returns true if "field" key exists in the hashmap. False otherwise. *');

 console.log(obj.hasOwnProperty("field"), 'obj.hasOwnProperty("field")', 'This statement returns true if \'field\' key exists in the hashmap. The ONLY way NOT to lookup for property in the prototype chain!');
 //Object.keys().indexOf() is an overkill that runs much slower :)

 var counter = 0,
     key;
 for (key in obj) {
     counter++;
 }
 console.assert(counter === 0, 'counter === 0', '"field" is not iterated using "for .. in" loop. *');

Hãy coi chừng Rò rỉ bộ nhớ!

Trong khi sử dụng obj[prop] = undefined nhanh hơn làm delete obj[prop], một yếu tố quan trọng khác là obj[prop] = undefined có thể không phải lúc nào cũng phù hợp. delete obj[prop] loại bỏ prop từ obj và xóa nó khỏi bộ nhớ trong khi obj[prop] = undefined chỉ đơn giản là đặt giá trị của prop đến undefined lá nào prop vẫn còn trong ký ức. Do đó, trong trường hợp có nhiều khóa được tạo và xóa, sử dụng obj[prop] = undefined có thể buộc điều chỉnh bộ nhớ tốn kém (khiến trang bị đóng băng) và có khả năng xảy ra lỗi ngoài bộ nhớ. Kiểm tra mã sau đây.

"use strict";
var theNodeList=[], i, current, numberOfNodes=65536, body=document.body, nodeRecords=[];
for (i = 0; i !== numberOfNodes; i++) {
    nodeRecords[i] = [];
    current = theNodeList[i] = document.createElement("div");
    current.textContent = i;
    document.body.appendChild( current );
}
var lastTime = -1;
requestAnimationFrame(function recordUpdates(){
    var currentTime = Math.round( performance.now()*1000 )
    for (i = 0; i !== numberOfNodes; i++) {
        if (lastTime !== -1) {
            // the previously collected data is no longer in use
            /*************************************************/
            /****/ nodeRecords[i][lastTime] = undefined; /****/
            /*************************************************/
        }
        nodeRecords[i][currentTime] = theNodeList[i].outerHTML;
    }
    lastTime = currentTime;
    requestAnimationFrame( recordUpdates );
});

Trong đoạn mã trên, chỉ cần làm nodeRecords[i][lastTime] = undefined; sẽ gây ra rò rỉ bộ nhớ lớn vì mỗi khung hình động. Mỗi khung, tất cả 65536 phần tử DOM sẽ chiếm một 65536 khe riêng lẻ, nhưng các khe 65536 trước đó sẽ chỉ được đặt thành không xác định để chúng treo trong bộ nhớ. Tiếp tục, hãy thử chạy mã trên trong bảng điều khiển và xem cho chính bạn. Sau khi buộc lỗi hết bộ nhớ, hãy thử chạy lại, ngoại trừ với phiên bản sau của mã sử dụng deletethay vào đó.

"use strict";
var theNodeList=[], i, current, numberOfNodes=65536, body=document.body, nodeRecords=[];
for (i = 0; i !== numberOfNodes; i++) {
    nodeRecords[i] = [];
    current = theNodeList[i] = document.createElement("div");
    current.textContent = i;
    document.body.appendChild( current );
}
var lastTime = -1;
requestAnimationFrame(function recordUpdates(){
    var currentTime = Math.round( performance.now()*1000 )
    for (i = 0; i !== numberOfNodes; i++) {
        if (lastTime !== -1) {
            // the previously collected data is no longer in use
            /********************************************/
            /****/ delete nodeRecords[i][lastTime]; /****/
            /********************************************/
        }
        nodeRecords[i][currentTime] = theNodeList[i].outerHTML;
    }
    lastTime = currentTime;
    requestAnimationFrame( recordUpdates );
});

Như đã thấy trong đoạn mã trên, có một số trường hợp sử dụng hiếm hoi thích hợp cho delete nhà điều hành. Tuy nhiên, đừng lo lắng về vấn đề này quá nhiều. Điều này sẽ chỉ trở thành một vấn đề với các đối tượng tuổi thọ dài mà có được các phím mới liên tục được thêm vào chúng. Trong mọi trường hợp khác (hầu như mọi trường hợp trong lập trình thế giới thực), nó là thích hợp nhất để sử dụng obj[prop] = undefined. Mục đích chính của phần này là chỉ mang lại sự chú ý của bạn để trong trường hợp hiếm có điều này trở thành vấn đề trong mã của bạn, bạn có thể dễ dàng hiểu vấn đề hơn và do đó không phải lãng phí giờ để giải mã mã của bạn và hiểu vấn đề này.

Không luôn đặt undefined

Một khía cạnh của Javascript quan trọng cần xem xét là tính đa hình. Đa hình là khi gán cùng một loại biến / vị trí trong một đối tượng khác nhau như được thấy bên dưới.

var foo = "str";
foo = 100;          // variable foo is now labeled polymorphic by the browser
var bar = ["Some", "example"];
bar[2] = "text";    // bar is a monomorphic array here because all its entries have the
                    // same type: string primitive
bar[1] = undefined; // bar is now a polymorphic array

Tuy nhiên, có hai vấn đề chính không thể giải quyết với mảng đa hình:

  1. Chúng chậm và bộ nhớ không hiệu quả. Khi truy cập vào một chỉ mục cụ thể, thay vì chỉ nhận được kiểu toàn cục cho mảng, trình duyệt thay vào đó phải có loại trên cơ sở từng chỉ mục, theo đó mỗi chỉ mục lưu trữ siêu dữ liệu bổ sung thuộc loại của nó.
  2. Một khi đa hình, luôn luôn đa hình. Khi một mảng được tạo thành đa hình, tính đa hình không thể được hoàn tác trong các trình duyệt Webkit. Vì vậy, ngay cả khi bạn khôi phục mảng đa hình thành không đa hình, nó vẫn sẽ được trình duyệt lưu trữ dưới dạng mảng đa hình.

Người ta có thể so sánh tính đa hình với nghiện ma túy. Thoạt nhìn, nó có vẻ hấp dẫn một cách đáng kinh ngạc: mã khá đẹp. Sau đó, coder giới thiệu mảng của họ với loại thuốc đa hình. Ngay lập tức, mảng đa hình trở nên kém hiệu quả hơn, và nó không bao giờ có thể trở nên hiệu quả như trước đây vì nó bị ma túy. Để tương quan hoàn cảnh như vậy với cuộc sống thực, một người nào đó trên cocaine thậm chí không có khả năng vận hành một tay nắm cửa đơn giản, ít có khả năng tính số của PI. Tương tự như vậy, một mảng trên thuốc đa hình không bao giờ có hiệu quả như một mảng đơn hình.

Nhưng, tương tự chuyến đi thuốc có liên quan như thế nào delete hoạt động? Câu trả lời kế thừa dòng mã cuối cùng trong đoạn mã ở trên. Vì vậy, hãy để nó được xem xét lại, lần này với một twist.

var bar = ["Some", "example"];
bar[2] = "text";    // bar is not a polymorphic array here because all its entries have the
                    // same type: string primitive
bar[1] = "";        // bar is still a monomorphic array
bar[1] = undefined; // bar is now a polymorphic array

Quan sát. bar[1] = "" không coerce đa hình trong khi bar[1] = undefined làm. Vì vậy, một nên luôn luôn, bất cứ khi nào có thể sử dụng các loại tương ứng cho các đối tượng của họ để không vô tình gây ra đa hình. Một người như vậy có thể sử dụng danh sách sau đây làm tài liệu tham khảo chung để giúp họ tiếp tục. Tuy nhiên, vui lòng không sử dụng rõ ràng các ý tưởng bên dưới. Thay vào đó, hãy sử dụng bất kỳ thứ gì hoạt động tốt cho mã của bạn.

  • Khi sử dụng một mảng / biến được nhập vào nguyên thủy boolean, hãy sử dụng false hoặc là undefined làm giá trị trống. Trong khi tránh đa hình không cần thiết là tốt, viết lại tất cả các mã của bạn để rõ ràng cấm nó sẽ có khả năng thực sự dẫn đến giảm hiệu suất. Sử dụng phán đoán chung!
  • Khi sử dụng một mảng / biến được nhập vào số nguyên thủy, hãy sử dụng 0 làm giá trị trống. Lưu ý rằng nội bộ, có hai loại số: số nguyên nhanh (2147483647 đến -2147483648 bao gồm) và tăng gấp đôi dấu chấm động chậm (bất cứ điều gì khác hơn bao gồm cả NaN và Infinity). Khi một số nguyên bị giáng cấp thành số double, nó không thể được đẩy lùi về một số nguyên.
  • Khi sử dụng một mảng / biến được nhập vào chuỗi nguyên thủy, hãy sử dụng "" làm giá trị trống.
  • Khi sử dụng Biểu tượng, hãy đợi, tại sao bạn sử dụng Biểu tượng?!?! Biểu tượng là juju xấu cho hiệu suất. Tất cả mọi thứ được lập trình để sử dụng Biểu tượng có thể được lập trình lại để không sử dụng Biểu tượng, dẫn đến mã nhanh hơn không có Biểu tượng. Biểu tượng thực sự chỉ là siêu siêu hiệu quả.
  • Khi sử dụng bất kỳ thứ gì khác, hãy sử dụng null.

Tuy nhiên, hãy chú ý! Đừng đột nhiên bắt đầu làm điều này với tất cả các mã từ trước của bạn bây giờ vì nó có khả năng sẽ phá vỡ các mã đã tồn tại từ trước và / hoặc giới thiệu các lỗi lạ. Thay vào đó, thực hành hiệu quả như vậy cần phải được thực hiện ngay từ đầu, và khi chuyển đổi từ trước, bạn nên kiểm tra gấp đôi, gấp ba lần, gấp bốn lần tất cả các dòng liên quan đến việc cố gắng nâng cấp mã cũ lên thực hành mới này rủi ro vì nó là bổ ích.


705
2018-02-12 17:48



một thuộc tính được gán cho undefined vẫn là thuộc tính của một đối tượng, do đó nó sẽ không bị GC xóa trừ khi bạn đọc sai đoạn cuối của mình. - Lance
Tôi đã sai khi chạm vào chủ đề của GC tại đây. Cả hai phương pháp đều có cùng kết quả cho GC: chúng loại bỏ giá trị được liên kết với khóa. Nếu giá trị đó là tham chiếu cuối cùng đối với một đối tượng khác, đối tượng đó sẽ được dọn sạch. - Dan
một thuộc tính được gán cho undefined vẫn là thuộc tính của một đối tượng, do đó nó sẽ không bị xóa bởi GC GC không quản lý bất kỳ điều gì về thuộc tính. Nó thu thập và loại bỏ các giá trị. Miễn là không có gì tham khảo một giá trị (một đối tượng, chuỗi, vv) nữa, GC sẽ loại bỏ nó khỏi bộ nhớ. - meandre
BTW, đó là vấn đề kép để kiểm tra nếu một tài sản tồn tại trên đối tượng Javascript. Sử dụng trong nhà điều hành là đáng tin cậy nhưng chậm. Kiểm tra xem thuộc tính có không chưa xác định "không phải là câu trả lời đúng" nhưng nó là một cách nhanh hơn. kiểm tra - rdllopes
Câu trả lời này vẫn có liên quan? jsperf hiện đang giảm, nhưng điểm chuẩn này dường như chỉ ra rằng sự chênh lệch tốc độ chỉ là 25%, không có nơi nào gần đến "~ 100 lần chậm hơn" trong câu trả lời này. - Cerbrus


var myObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};
    
delete myObject.regex;

console.log ( myObject.regex); // logs: undefined

Điều này làm việc trong Firefox và Internet Explorer, và tôi nghĩ nó hoạt động trong tất cả những thứ khác.


193
2017-10-16 11:03



Có cách nào để xóa nhiều thuộc tính từ cùng một mảng bằng một biểu thức không - Aakriti.G
Khi cố gắng xóa nhiều thuộc tính cùng một lúc, sẽ không tốt hơn nếu chỉ remap đối tượng mới? - jasonscript


Cập nhật 2018-07-21: Trong một thời gian dài, tôi cảm thấy xấu hổ về câu trả lời này, vì vậy tôi nghĩ đã đến lúc tôi chạm vào nó một chút. Chỉ cần một chút bình luận, làm rõ và định dạng để giúp đẩy nhanh việc đọc các phần không cần thiết dài và phức tạp của câu trả lời này.


PHIÊN BẢN NGẮN

Câu trả lời thực tế cho câu hỏi

Như những người khác đã nói, bạn có thể sử dụng delete.

obj // {"foo": "bar"}
delete obj["foo"]
obj // {}
obj["foo"] // undefined

Tương đương mảng

Đừng delete từ một mảng. Sử dụng Array.prototype.splice thay thế.

arr // [1,2,3,4,5]
arr.splice(3,1); // 4
arr // [1,2,3,5]

PHIÊN BẢN DÀI HẠN

JavaScript là một ngôn ngữ OOP, vì vậy mọi thứ đều là một đối tượng, bao gồm mảng. Vì vậy, tôi cảm thấy cần thiết để chỉ ra một cảnh báo cụ thể.

Trong mảng, không giống như các đối tượng cũ, sử dụng delete để lại rác thải dưới dạng null, tạo ra một "lỗ hổng" trong mảng.

var array = [1, 2, 3, 4];
delete array[2];
/* Expected result --> [1, 2, 4]
 * Actual result   --> [1, 2, null, 4]
 */

Bạn có thể thấy, delete không phải lúc nào cũng hoạt động như mong đợi. Giá trị được ghi đè, nhưng bộ nhớ không được phân bổ lại. Điều đó có nghĩa là, array[4] không được chuyển đến array[3]. Trái ngược với Array.prototype.unshift, chèn một phần tử vào đầu mảng và dịch chuyển mọi thứ lên (array[0] trở thành array[1], v.v.)

Thành thật mà nói, ngoài việc thiết lập null thay vì undefined- điều lạ lùng - hành vi này không nên thật đáng ngạc nhiên, vì delete là một toán tử đơn nhất, như typeof, đó là khó đun sôi trong ngôn ngữ và không phải quan tâm đến kiểu đối tượng đang được sử dụng, trong khi Array là một phân lớp của Object với phương pháp được thiết kế đặc biệt cho làm việc với mảng. Vì vậy, không có lý do chính đáng cho deleteđể có một trường hợp đặc biệt được nấu chín để tái chuyển mảng, vì điều đó sẽ làm chậm mọi thứ xuống với công việc không cần thiết. Nhìn lại, kỳ vọng của tôi là không thực tế.

Tất nhiên là nó đã làm làm tôi ngạc nhiên. Bởi vì tôi đã viết điều này để biện minh cho cuộc thập tự chinh của tôi chống lại "rác rỗng":

Bỏ qua những nguy hiểm và các vấn đề vốn có trong nullvà không gian lãng phí, điều này có thể có vấn đề nếu mảng cần phải chính xác.

Đó là một lý do khủng khiếp để loại bỏ nullS--null chỉ nguy hiểm nếu được sử dụng không đúng cách và không liên quan gì đến "độ chính xác". Lý do thực sự bạn không nên delete từ một mảng là vì để lại các cấu trúc dữ liệu đầy rác và lộn xộn xung quanh là cẩu thả và dễ bị lỗi.

Điều sau đây là một kịch bản giả tạo khá dài, vì vậy bạn có thể bỏ qua phần này, Giải pháp, nếu bạn muốn. Lý do duy nhất tôi rời khỏi phần này là bởi vì tôi nghĩ một số người có thể nghĩ rằng nó buồn cười, và tôi không muốn trở thành "anh chàng đó", những người đăng một câu trả lời "vui" và sau đó xóa tất cả các "funny" từ nó sau này .

... Thật là ngu ngốc, tôi biết.

Kịch bản PDP-11 bị kéo dài và kéo dài

Ví dụ: giả sử bạn đang tạo một ứng dụng web sử dụng tuần tự hóa JSON để lưu trữ một mảng được sử dụng cho 'tab' trong một chuỗi (trong trường hợp này, localStorage). Hãy cũng nói rằng mã sử dụng các chỉ số số của các thành viên của mảng để "tiêu đề" chúng khi vẽ lên màn hình. Tại sao bạn làm điều này thay vì chỉ lưu trữ "tiêu đề"? Bởi vì... lý do.

Được rồi, chúng ta hãy nói rằng bạn đang cố gắng tiết kiệm bộ nhớ theo yêu cầu của điều này một người dùng chạy một máy tính mini PDP-11 từ năm 1960 chạy UNIX, và đã viết trình duyệt dựa trên Elinks, phù hợp với JavaScript, trình duyệt thân thiện với máy in của riêng mình vì X11 là ra câu hỏi.

Kịch bản cạnh trường hợp ngày càng ngu ngốc sang một bên, sử dụng delete trên mảng đã nói sẽ dẫn đến null gây ô nhiễm mảng và có thể gây ra lỗi trong ứng dụng sau này. Và nếu bạn kiểm tra null, nó sẽ thẳng lên bỏ qua các con số dẫn đến các tab được hiển thị như [1] [2] [4] [5] ....

if (array[index] == null)
    continue;
else
    title = (index + 1).toString();
/* 0 -> "1"
 * 1 -> "2"
 * 2 -> (nothing)
 * 3 -> "4"
 */

Vâng, đó chắc chắn không phải những gì bạn muốn.

Bây giờ bạn có thể giữ một trình lặp thứ hai, như j, để tăng chỉ khi giá trị hợp lệ được đọc từ mảng. Nhưng điều đó sẽ không giải quyết chính xác null vấn đề, và bạn vẫn phải làm hài lòng chơi khăm Người dùng PDP-11. Than ôi, máy tính của anh ấy không có đủ bộ nhớ để giữ số nguyên cuối cùng (không hỏi làm thế nào anh ta quản lý để xử lý một mảng có chiều rộng biến ...).

Vì vậy, anh ta gửi cho bạn một email trong sự tức giận:

Hey, your webapp broke my browser! I checked my localStorage database after your stupid code made my browser segfault, and this is what I found:

>"tabs:['Hello World', 'foo bar baz', null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, ... ]"

After clearing my precious data, it segfaulted again, and I did a backtrace, and what do I find? WHAT DO I FIND!? YOU USE TOO MANY VARIABLES!

>var i = index;
>var j = 1;

Grr, I am angry now.
-Troll Davidson

Về bây giờ, bạn đang ở cuối wit của bạn. Anh chàng này đã phàn nàn không ngừng về ứng dụng của bạn, và bạn muốn bảo anh ta im lặng và đi lấy một chiếc máy tính tốt hơn.

Giải pháp: Array.prototype.splice

May mắn thay, mảng làm có một phương pháp chuyên biệt để xóa các chỉ mục và tái phân bổ bộ nhớ: Array.prototype.splice(). Bạn có thể viết một cái gì đó như thế này:

Array.prototype.remove = function(index){
  this.splice(index,1);
}
...
array = [1, 2, 3, 4];
array.remove(2);
// Result -> [1, 2, 4]

Và cứ như thế, bạn đã hài lòng với ông PDP-11. Hoan hô! (Tôi vẫn nói với anh ta, mặc dù ...)

Array.prototype.splice vs Array.prototype.slice

Tôi cảm thấy điều quan trọng là chỉ ra sự khác biệt giữa hai chức năng có tên tương tự này, vì chúng đều rất hữu ích.

Array.prototype.splice (bắt đầu, n)

.splice() thay đổi mảng và trả về các chỉ mục đã loại bỏ. Mảng được cắt lát bắt đầu từ chỉ mục, startn các yếu tố được cắt ra. Nếu n không xác định, toàn bộ mảng sau start bị cắt lát (n = array.length - start).

let a = [5,4,3,2,1];
let chunk = a.splice(2,2);

// a     [5,4,3,2,1]
// start  0 1 2 - -
// n      - - 1 2 -

chunk; // [3,2]
a;     // [5,4,1]

Array.prototype.slice (bắt đầu, kết thúc)

.slice() không phá hủy và trả về một mảng mới chứa các chỉ số được chỉ định từ start đến end. Nếu end không được chỉ định, hành vi cũng giống như .splice() (end = array.length). Hành vi này hơi phức tạp một chút, vì một lý do nào đó, end các chỉ mục từ 1 thay vì 0. Tôi không biết tại sao nó lại làm như vậy, nhưng đó là cách thực hiện. Còn nếu end <= start, kết quả là một mảng trống.

let a = [5,4,3,2,1];
let chunks = [
    a.slice(2,0),
    a.slice(2,2),
    a.slice(2,3),
    a.slice(2,5) ];

// a             [5,4,3,2,1]
// start          0 1 2 - -
// end, for...    - - - - -
//   chunks[0]  0 - - - - -   
//   chunks[1]    1 2 - - -
//   chunks[2]    1 2 3 - -
//   chunks[3]    1 2 3 4 5

chunks; // [ [], [], [3], [3,2,1] ]
a;      // [5,4,3,2,1]

Đó thực sự không phải là những gì đang xảy ra, nhưng nó dễ dàng hơn để nghĩ theo cách đó. Theo MDN, đây là những gì thực sự xảy ra:

// a             [5,4,3,2,1]
// start          0 1 2 - - -
// end, for...    - - - - - -
//   chunks[0]    0 - - - - -
//   chunks[1]    0 1 2 - - -
//   chunks[2]    0 1(2)3 - -
//   chunks[3]    0 1(2 3 4)5

Chỉ số được chỉ định bởi end chỉ đơn giản là bị loại trừ khỏi slice. Các chỉ số được đánh dấu cho biết những gì bị cắt. Dù bằng cách nào, hành vi không trực quan và nó bị ràng buộc gây ra chia sẻ công bằng của các lỗi off-by-one, vì vậy bạn có thể thấy hữu ích khi tạo một hàm bao bọc để mô phỏng chặt chẽ hơn hành vi của .splice():

function ez_slice(array, start = 0, n = null){
    if(!Array.isArray(array) || !is_number(start))
        return null;

    if(is_number(n))
        return array.slice(start, start + n);

    if(n === null)
        return array.slice(start);

    return null;
}

ez_slice([5,4,3,2,1], 2, 1) // [3]
ez_slice([5,4,3,2,1], 2)    // [3,2,1]

/* Fun fact: isNaN is unreliable.
 * [NaN, [], {}, 0, 1, Infinity, undefined, null, "Hi"].filter(isNaN)
 * [NaN, {}, undefined, "Hi"]
 *
 * What we want is...
 *
 * [NaN, [], {}, 0, 1, Infinity, undefined, null, "Hi"].filter(is_nan)
 * [NaN]
 */
function is_nan(num){
    return typeof num === "number"
        && num !== num;
}

function is_number(num){
    return !is_nan(num)
        && typeof num === "number"
        && isFinite(num);
}

Lưu ý rằng hàm wrapper được thiết kế rất nghiêm ngặt về các loại và sẽ trả về null nếu bất cứ điều gì là tắt. Điều đó bao gồm việc đưa vào một chuỗi như "3". Nó được để lại cho các lập trình viên phải siêng năng về các loại của mình. Điều này là để khuyến khích thực hành lập trình tốt.

Cập nhật liên quan is_array()

Điều này liên quan đến đoạn mã này (hiện đã bị loại bỏ):

function is_array(array){
    return array !== null
        && typeof array === "object"
        && typeof array.length !== "undefined"
        && array.__proto__ === Array.prototype;
}

Vì vậy, khi nó quay ra, thực sự IS là một cách tích hợp để biết liệu một mảng có thực sự là một mảng hay không, và đó là Array.isArray(), được giới thiệu trong ECMAScript 5 (tháng 12 năm 2009). Tôi tìm thấy điều này trong khi tìm cách để xem liệu có một câu hỏi hỏi về việc nói các mảng từ các vật thể hay không, để xem liệu có một giải pháp nào tốt hơn của tôi không, hoặc để thêm tôi nếu không có. Vì vậy, nếu bạn đang sử dụng phiên bản JavaScript sớm hơn ECMA 5, thì có phần chèn sẵn của bạn. Tuy nhiên, tôi khuyên bạn không nên sử dụng is_array() chức năng, khi tiếp tục hỗ trợ các phiên bản JavaScript cũ có nghĩa là tiếp tục hỗ trợ các trình duyệt cũ triển khai chúng, có nghĩa là khuyến khích sử dụng phần mềm không an toàn và khiến người dùng có nguy cơ bị phần mềm độc hại. Vì vậy, xin vui lòng, sử dụng Array.isArray(). Sử dụng let và const. Sử dụng các tính năng mới được thêm vào ngôn ngữ. Đừng sử dụng tiền tố của nhà cung cấp. Xóa bỏ rằng IE polyfill crap từ trang web của bạn. Xóa XHTML đó <!CDATA[[... chúng tôi đã chuyển sang HTML5 vào năm 2014. Mọi người sớm càng rút lại hỗ trợ cho những trình duyệt cũ / bí truyền này, các nhà cung cấp trình duyệt sẽ sớm thực sự tuân thủ tiêu chuẩn web và nắm lấy công nghệ mới, và chúng tôi có thể chuyển sang một trang web an toàn hơn.


134
2017-09-18 00:56



Điều này delete từ khóa, tuy nhiên, thuận tiện hơn nhiều, lol - Braden Best
Cách tiếp cận này không sửa đổi đối tượng gốc có thể vẫn được tham chiếu ở nơi khác. Điều này có thể hoặc có thể không phải là một vấn đề tùy thuộc vào cách nó được sử dụng nhưng nó là một cái gì đó để ghi nhớ. - Tamas Czinege
@ B1KMusic Đây là cách để xóa một phần tử khỏi một mảng: mối nối - wulftone
@wulftone nope, chia tách mảng và không làm gì để xóa một giá trị. Tôi thực sự nghĩ cách tốt nhất để xóa khỏi một mảng nơi cần xóa các giá trị cụ thể để sử dụng delete và tạo một chức năng Thu gom rác để làm sạch nó. - Braden Best
Tôi không thấy splice trong bản chỉnh sửa của bạn, nhưng remove nên là Array.prototype.remove = function(index) { this.splice(index, 1); }; - Ry-♦


Câu hỏi cũ, câu trả lời hiện đại. Sử dụng phá hủy đối tượng, một ECMAScript 6 tính năng, nó đơn giản như:

const { a, ...rest } = { a: 1, b: 2, c: 3 };

Hoặc với mẫu câu hỏi:

const myObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};
const { regex, ...newObject } = myObject;
console.log(newObject);

Bạn có thể thấy nó hoạt động trong trình soạn thảo thử Babel.


Chỉnh sửa:

Để gán lại cho cùng một biến, hãy sử dụng let:

let myObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};
({ regex, ...myObject } = myObject);
console.log(myObject);

92
2017-11-08 18:02



Có lẽ vì mục tiêu là để loại bỏ một tài sản từ một đối tượng, không phải để tạo ra một tài sản mới mà không có tài sản ... mặc dù, giải pháp của bạn là yêu thích của tôi, vì tôi thích cách bất biến. - Vingt_centimes
Câu hỏi đã nêu "để kết thúc với Mới myObject ". - Koen.
Theo kangax.github.io/compat-table/esnext, các thuộc tính còn lại của đối tượng không được hoàn thành cho ES6, không có triển khai trình duyệt nào và chỉ Babel cung cấp hỗ trợ. - Justin C
Điều này thực sự là một lớp lót ngọt cho việc gán đối tượng mới mà không có các đạo cụ không mong muốn, và đã được hỗ trợ với Node.js 8. * / 9. * với --harmony: node.green/… - Damaged Organic
Đây sẽ là câu trả lời được chấp nhận vào năm 2018 :) - Yulian


Một cách khác là sử dụng Underscore.js thư viện.

Lưu ý rằng _.pick() và _.omit() cả hai trả về một bản sao của đối tượng và không trực tiếp sửa đổi đối tượng gốc. Gán kết quả cho đối tượng ban đầu nên thực hiện thủ thuật (không được hiển thị).

Tài liệu tham khảo: liên kết  _.pick (đối tượng, * khóa)

Trả về một bản sao của đối tượng, được lọc để chỉ có các giá trị cho các khóa có trong danh sách trắng (hoặc dãy các khóa hợp lệ).

var myJSONObject = 
{"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};

_.pick(myJSONObject, "ircEvent", "method");
=> {"ircEvent": "PRIVMSG", "method": "newURI"};

Tài liệu tham khảo: liên kết  _.omit (đối tượng, * khóa)

Trả về một bản sao của đối tượng, được lọc để bỏ qua các khóa danh sách đen (hoặc dãy khóa).

var myJSONObject = 
{"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};

_.omit(myJSONObject, "regex");
=> {"ircEvent": "PRIVMSG", "method": "newURI"};

Đối với mảng, _.filter() và _.reject() có thể được sử dụng theo cách tương tự.


67
2018-05-24 18:53



Hãy nhớ rằng nếu các khóa của đối tượng là số, bạn có thể cần phải _.omit(collection, key.toString()) - Jordan Arseno
Tại sao bạn liên kết với Wikipedia, và không underscorejs.org? - E730
@ E730 Câu hỏi hay. Tôi không biết tại sao một trong những người chỉnh sửa đã thay đổi nó thành wikipedia.org/wiki/Underscore.js. Tôi đã đổi nó thành underscorejs.org. - Thaddeus Albers
Hmmmmm .... Dấu gạch dưới là ~ 100x chậm hơn delete obj[prop] chậm hơn 100 lần so với obj[prop] = undefined. - Jack Giffin


Cụm từ bạn đã sử dụng trong tiêu đề câu hỏi của mình Remove a property from a JavaScript object, có thể được diễn giải theo một số cách khác nhau. Một là loại bỏ nó cho toàn bộ bộ nhớ và danh sách các khóa đối tượng hoặc khác là chỉ để loại bỏ nó khỏi đối tượng của bạn. Vì nó đã được đề cập trong một số câu trả lời khác, delete từ khóa là phần chính. Giả sử bạn có đối tượng như:

myJSONObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};

Nếu bạn làm:

console.log(Object.keys(myJSONObject));

kết quả sẽ là:

["ircEvent", "method", "regex"]

Bạn có thể xóa khóa cụ thể đó khỏi các khóa đối tượng của mình như:

delete myJSONObject["regex"];

Sau đó, khóa đối tượng của bạn sử dụng Object.keys(myJSONObject) sẽ là:

["ircEvent", "method"]

Nhưng vấn đề là nếu bạn quan tâm đến bộ nhớ và bạn muốn toàn bộ đối tượng bị xóa khỏi bộ nhớ, bạn nên đặt nó thành null trước khi bạn xóa khóa:

myJSONObject["regex"] = null;
delete myJSONObject["regex"];

Điểm quan trọng khác ở đây là phải cẩn thận về các tham chiếu khác của bạn cho cùng một đối tượng. Ví dụ, nếu bạn tạo một biến như:

var regex = myJSONObject["regex"];

Hoặc thêm nó như là một con trỏ mới cho một đối tượng khác như:

var myOtherObject = {};
myOtherObject["regex"] = myJSONObject["regex"];

Sau đó, ngay cả khi bạn xóa nó khỏi đối tượng của bạn myJSONObject, đối tượng cụ thể đó sẽ không bị xóa khỏi bộ nhớ, vì regex biến và myOtherObject["regex"] vẫn có giá trị của chúng. Sau đó, làm thế nào chúng ta có thể loại bỏ các đối tượng từ bộ nhớ cho chắc chắn?

Câu trả lời sẽ là xóa tất cả các tham chiếu bạn có trong mã của bạn, chỉ vào chính đối tượng đó và cũng không dùng var câu lệnh để tạo tham chiếu mới cho đối tượng đó. Điểm cuối cùng này liên quan đến var tuyên bố, là một trong những vấn đề quan trọng nhất mà chúng ta thường gặp phải, bởi vì sử dụng var các câu lệnh sẽ ngăn không cho đối tượng đã tạo bị xóa.

Điều này có nghĩa là trong trường hợp này, bạn sẽ không thể xóa đối tượng đó vì bạn đã tạo regex biến thông qua một var và nếu bạn làm như vậy:

delete regex; //False

Kết quả sẽ là false, có nghĩa là câu lệnh xóa của bạn chưa được thực thi như bạn mong đợi. Nhưng nếu bạn chưa tạo biến đó trước đây, và bạn chỉ có myOtherObject["regex"] là tham chiếu hiện tại cuối cùng của bạn, bạn có thể thực hiện việc này chỉ bằng cách xóa tham chiếu đó như:

myOtherObject["regex"] = null;
delete myOtherObject["regex"];

Nói cách khác, một đối tượng JavaScript bị tiêu diệt ngay sau khi không có tham chiếu nào trong mã của bạn được trỏ tới đối tượng đó.


Cập nhật: Nhờ @AgentME:

Đặt thuộc tính thành null trước khi xóa nó không thực hiện   bất cứ điều gì (trừ khi đối tượng đã được niêm phong bởi Object.seal và   xóa không thành công. Đó không phải là trường hợp thường trừ khi bạn đặc biệt   thử).

Để biết thêm thông tin về Object.seal: Object.seal ()


34
2018-02-12 06:29



Bạn sai - chỉ các đối tượng được chuyển bởi tham chiếu trong JavaScript, vì vậy nếu myJSONObject.regex's value là một chuỗi và bạn gán nó cho một số đối tượng khác, đối tượng khác có một bản sao của giá trị này. - Michał Perłakowski
Bạn nói đúng và đây là câu trích dẫn: "hãy cẩn thận về các tham chiếu khác của bạn cho cùng một đối tượng." - Mehran Hatami


Giả sử bạn có một đối tượng giống như sau:

var Hogwarts = {
    staff : [
        'Argus Filch',
        'Filius Flitwick',
        'Gilderoy Lockhart',
        'Minerva McGonagall',
        'Poppy Pomfrey',
        ...
    ],
    students : [
        'Hannah Abbott',
        'Katie Bell',
        'Susan Bones',
        'Terry Boot',
        'Lavender Brown',
        ...
    ]
};

Xóa thuộc tính đối tượng

Nếu bạn muốn sử dụng toàn bộ staff mảng, cách thích hợp để làm điều này, sẽ là để làm điều này:

delete Hogwarts.staff;

Ngoài ra, bạn cũng có thể làm điều này:

delete Hogwarts['staff'];

Tương tự, việc loại bỏ toàn bộ mảng học sinh sẽ được thực hiện bằng cách gọi delete Hogwarts.students; hoặc là delete Hogwarts['students'];.

Xóa chỉ mục mảng

Bây giờ, nếu bạn muốn loại bỏ một nhân viên hoặc sinh viên, thủ tục này hơi khác một chút, bởi vì cả hai thuộc tính đều là mảng.

Nếu bạn biết chỉ số của nhân viên của bạn, bạn có thể chỉ cần làm điều này:

Hogwarts.staff.splice(3, 1);

Nếu bạn không biết chỉ mục, bạn cũng sẽ phải thực hiện tìm kiếm chỉ mục:

Hogwarts.staff.splice(Hogwarts.staff.indexOf('Minerva McGonnagall') - 1, 1);

chú thích

Mặc dù về mặt kỹ thuật bạn có thể sử dụng delete cho một mảng, sử dụng nó sẽ dẫn đến kết quả không chính xác khi gọi ví dụ Hogwarts.staff.length sau này. Nói cách khác, delete sẽ xóa phần tử, nhưng nó sẽ không cập nhật giá trị của length bất động sản. Sử dụng delete cũng sẽ làm hỏng lập chỉ mục của bạn.

Vì vậy, khi xóa các giá trị từ một đối tượng, trước tiên hãy cân nhắc xem liệu bạn có đang xử lý các thuộc tính đối tượng hoặc cho dù bạn đang xử lý các giá trị mảng hay không và chọn chiến lược thích hợp dựa trên đó.

Nếu bạn muốn thử nghiệm với điều này, bạn có thể sử dụng Fiddle này như một điểm khởi đầu.


30
2018-02-21 18:09



Tôi nghĩ bạn nên luôn sử dụng splice trên một mảng thay vì delete. - Joel Trauger
@ JoelTrauger: Đó là những gì tôi đang nói ;-) - John Slegers
Vâng. Nhận xét của tôi là rằng delete thậm chí không nên là một điều. nó là splice là những gì OP đang tìm kiếm. - Joel Trauger
@ JoelTrauger: Như tôi đã cố giải thích, delete nên được sử dụng cho các thuộc tính đối tượng và splice cho các phần tử mảng. - John Slegers
Splice rất chậm. Mặc dù nó nên được sử dụng thay vì delete trên mảng, nó sẽ là khôn ngoan nhất để không tạo ra mã tập trung xung quanh nó cả. - Jack Giffin


ECMAScript 2015 (hoặc ES6) được tích hợp sẵn Phản chiếu vật. Có thể xóa thuộc tính đối tượng bằng cách gọi Reflect.deleteProperty () với đối tượng đích và khóa thuộc tính làm tham số:

Reflect.deleteProperty(myJSONObject, 'regex');

tương đương với:

delete myJSONObject['regex'];

Nhưng nếu thuộc tính của đối tượng không thể cấu hình được thì không thể xóa nó với chức năng deleteProperty hoặc xóa toán tử:

let obj = Object.freeze({ prop: "value" });
let success = Reflect.deleteProperty(obj, "prop");
console.log(success); // false
console.log(obj.prop); // value

Object.freeze () làm cho tất cả các thuộc tính của đối tượng không thể cấu hình (bên cạnh những thứ khác). deleteProperty chức năng (cũng như toán tử xóa) trả về false khi cố xóa bất kỳ thuộc tính nào của nó. Nếu thuộc tính được cấu hình, nó trả về true, ngay cả khi tài sản không tồn tại.

Sự khác biệt giữa delete và deleteProperty là khi sử dụng chế độ nghiêm ngặt:

"use strict";

let obj = Object.freeze({ prop: "value" });
Reflect.deleteProperty(obj, "prop"); // false
delete obj["prop"];
// TypeError: property "prop" is non-configurable and can't be deleted

29
2018-01-10 16:36



@Gothdo nó có nhiều lợi ích hơn, đặc biệt là khi bạn cần phải làm một số công cụ chức năng. Ví dụ. bạn có thể gán hàm cho biến, chuyển làm đối số hoặc sử dụng apply, call, bind chức năng... - madox2


Các toán tử xóa là cách tốt nhất để làm như vậy.

Một ví dụ trực tiếp để hiển thị:

var foo = {bar: 'bar'};
delete foo.bar;
console.log('bar' in foo); // Logs false, because bar was deleted from foo.

22
2018-04-28 05:14



Nó có thể đáng chú ý là mặc dù sử dụng delete nhà điều hành là khỏe mạnh liên quan đến thu gom rác thải, nó có thể bất ngờ chậm, không phải là một phần nhỏ cho cùng một lý do. - John Weisz