Loại bỏ các thuộc tính trống / giá trị giả khỏi Đối tượng bằng Underscore.js


83

Tôi có một đối tượng với một số thuộc tính. Tôi muốn xóa bất kỳ thuộc tính nào có giá trị sai.

Điều này có thể đạt được với compactmảng, nhưng đối với đối tượng thì sao?


Để tránh sao chép dán phần này qua các kho, bạn có thể sử dụng Bit để nhập thành phần này (đã vượt qua 3 bài kiểm tra và giấy phép MIT). Bạn cũng có thể thử gói NPM này (có thể là quá mức cần thiết cho một thành phần nhỏ).
Yoni

Câu trả lời:


47

Bạn có thể tạo plugin gạch dưới (mixin) của riêng mình:

_.mixin({
  compactObject: function(o) {
    _.each(o, function(v, k) {
      if(!v) {
        delete o[k];
      }
    });
    return o;
  }
});

Và sau đó sử dụng nó như một phương pháp gạch dưới gốc:

var o = _.compactObject({
  foo: 'bar',
  a: 0,
  b: false,
  c: '',
  d: null,
  e: undefined
});

Cập nhật

Như @AndreiNeculau đã chỉ ra , mixin này ảnh hưởng đến đối tượng gốc, trong khi compactphương thức gạch dưới gốc trả về bản sao của mảng .
Để giải quyết vấn đề này và làm cho compactObjecthành vi của chúng tôi giống như anh em họ hơn , đây là một cập nhật nhỏ:

_.mixin({
  compactObject : function(o) {
     var clone = _.clone(o);
     _.each(clone, function(v, k) {
       if(!v) {
         delete clone[k];
       }
     });
     return clone;
  }
});

1
Vì câu hỏi có tham chiếu gạch dưới, nên sẽ rất tốt nếu nó không hoạt động như thế nào _.compact. Nó sẽ xóa các thuộc tính, thay vì tạo một bản sao nông chỉ với các giá trị trung thực. Xem stackoverflow.com/a/19750822/465684 bên dưới
Andrei Neculau

@AndreiNeculau Bạn nói đúng! Tôi dường như đã bỏ lỡ điều đó sớm hơn. Xem câu trả lời cập nhật của tôi.
gion_13 Ngày

3
Tại sao đầu tiên sao chép tất cả các thuộc tính của một đối tượng, sau đó lặp qua chúng và xóa những thuộc tính giả? Đó là không tốt. Hơn nữa, việc sử dụng deletenói chung không được khuyến khích vì nó ngay lập tức làm lộ ra các thuộc tính có cùng tên từ chuỗi nguyên mẫu và cũng ảnh hưởng đến hiệu suất do "lớp ẩn" (V8) - việc thay đổi cấu trúc đối tượng khiến động cơ phải làm việc thêm. Giải pháp tốt nhất và ngắn nhất sẽ là _.pick(o, _.identity).
Radko Dinev

170

Kể từ phiên bản Underscore 1.7.0, bạn có thể sử dụng _.pick:

_.pick(sourceObj, _.identity)

Giải trình

Tham số thứ hai _.pickcó thể là một hàm vị từ để chọn giá trị. Các giá trị mà vị từ trả về true được chọn và các giá trị mà vị từ trả về falsy bị bỏ qua.

pick _.pick (đối tượng, phím *)

Trả lại bản sao của đối tượng , được lọc để chỉ có các giá trị cho các khóa trong danh sách trắng (hoặc mảng khóa hợp lệ). Ngoài ra, chấp nhận một vị từ cho biết phím nào cần chọn.

_.identitylà một hàm trợ giúp trả về đối số đầu tiên của nó, có nghĩa là nó cũng hoạt động như một hàm vị từ để chọn các giá trị trung thực và loại bỏ các giá trị sai. Thư viện Underscore cũng đi kèm với một loạt các vị từ khác, chẳng hạn như _.pick(sourceObj, _.isBoolean)sẽ chỉ giữ lại các thuộc tính boolean.

Nếu bạn sử dụng kỹ thuật này nhiều, bạn có thể muốn làm cho nó biểu cảm hơn một chút:

var pickNonfalsy = _.partial(_.pick, _, _.identity); // Place this in a library module or something
pickNonfalsy(sourceObj);

Dấu gạch dưới phiên bản 1.6.0 cũng được cung cấp _.pick, nhưng nó không chấp nhận một hàm vị ngữ thay vì một danh sách trắng.


2
Đặc biệt cảm ơn vì đã đề cập đến _.identitychức năng, rất tiện dụng.
ivkremer

9
Điều này đã được cực kỳ tiện dụng! Nó cũng có thể sử dụng _.omit(sourceObj, _.isUndefined)để loại bỏ chỉ các giá trị không xác định (cho phép false, null, 0).
Ben Patterson,

1
Nó cũng có thể làm pick(obj, Boolean)để loại bỏ các giá trị falsey rằng cách tiếp cận tương tự có thể được sử dụng khi arr.filter(Boolean)để làm sạch một mảng từ các giá trị falsey ...
David Chase

3
Trong ES6, điều này biến thành_.pick(sourceObj, prop => prop)
Deniz Ozger

16
Trong lodash 4.4.0 _.picktác phẩm với những cái tên bất động sản, cho chức năng này như đã đề cập trong bài viết sử dụng_.pickBy
zooblin

45

Quick 'n Clear: _.omitBy( source, i => !i );

Điều này được phát biểu theo kiểu nghịch đảo với câu trả lời của Emil. Bằng cách này imho đọc rõ ràng hơn; nó tự giải thích hơn.

Hơi kém sạch sẽ nếu bạn không có sự sang trọng của ES6: _.omitBy( source, function(i){return !i;});

Luân phiên: _.omitBy( source, _.isEmpty)

Việc sử dụng _.isEmpty, thay vì tính xác _.identitythực, cũng sẽ thuận tiện loại bỏ các mảng và đối tượng trống khỏi bộ sưu tập và có thể loại bỏ số và ngày một cách bất tiện . Do đó, kết quả KHÔNG phải là câu trả lời chính xác cho câu hỏi của OP, tuy nhiên nó có thể hữu ích khi tìm cách loại bỏ các tập hợp rỗng.


8
Trong Lodash 4.0, chức năng này hiện đã được sử dụng omitBy. lodash.com/docs#omitBy
JackMorrissey,

3
Tôi tin rằng đây là giống như: _.pick(source, i => i); mà tránh sự phủ định
Jeff Lowery

2
@JeffLowery Điều này thậm chí còn tốt hơn, trong Lodash, vì vị từ mặc định là hàm nhận dạng! _.pickBy(source)là tất cả những gì cần thiết.
Shibumi 23/02/18

Lưu ý: Các số được coi là trống. _.isEmpty(5) === true. Do đó các giá trị là số sẽ bị loại bỏ.
Sir.Nathan Stassen

21

Với sự biến đổi của lodash ,

_.transform(obj, function(res, v, k) {
  if (v) res[k] = v;
});

23
whit lodash's _.pick (obj, _.identity); ngắn hơn ^ _ ^
evilive

Câu trả lời này hoặc bình luận của @ evilive dưới nó LÀ câu trả lời.
Radko Dinev

2
một biến thể ngắn hơn, dựa trên những nhận xét trên, sẽ làvar compactObject = _.partialRight(_.pick, _.identity);
zaboco


yse, _.pickBy(object)là tất cả những gì bạn cần
wdetac

19
Object.keys(o).forEach(function(k) {
    if (!o[k]) {
        delete o[k];
    }
});

1
Và người ta có thể sử dụng dấu gạch dưới cho .keys.forEach.
Felix Kling

Sau đó, điều này sẽ trông như thế nào trong Dấu gạch dưới? Đang cố gắng để mảnh nó lại với nhau ...

+1 đây là người đàn ông tuyệt vời. xin vui lòng cho tôi liên kết của forEachphương pháp JS
diEcho


9

Bạn có thể tạo một bản sao nông:

_(obj).reduce(function(a,v,k){ 
     if(v){ a[k]=v; } 
     return a; 
},{});

5

cho đối tượng sử dụng xóa.

for(var k in obj){

  if(obj.hasOwnProperty(k) && !obj[k]){
    delete obj[k];
  }
}

kể từ khi ông muốn một giải pháp gạch dưới, bạn có thể lặp qua mảng sử dụng một trong những phương pháp gạch của
gion_13

5

Đột nhiên, tôi cần tạo một hàm để loại bỏ các lỗi sai đệ quy. Tôi hi vọng cái này giúp được. Tôi đang sử dụng Lodash.

var removeFalsies = function (obj) {
    return _.transform(obj, function (o, v, k) {
        if (v && typeof v === 'object') {
            o[k] = _.removeFalsies(v);
        } else if (v) {
            o[k] = v;
        }
    });
};

_.mixin({ 'removeFalsies': removeFalsies });

Sau đó, bạn có thể sử dụng nó:

var o = _.removeFalsies({
  foo: 'bar',
  a: 0,
  b: false,
  c: '',
  d: null,
  e: undefined,
  obj: {
    foo: 'bar',
    a: 0,
    b: false,
    c: '',
    d: null,
    e: undefined
  }
});

// {
//   foo: 'bar',
//   obj: {
//     foo: 'bar'
//   }
// }

1

Để thêm vào câu trả lời của gion_13:

_.mixin({
  compactObject : function(o) {
     var newObject = {};
     _.each(o, function(v, k) {
       if(v !== null && v !== undefined) {
         newObject[k] = v
       }
     });
     return newObject;
  }
});

Điều này tạo một đối tượng mới và thêm các khóa và giá trị thay vì sao chép mọi thứ và xóa các cặp khóa-giá trị. Sự khác biệt nhỏ.

Nhưng quan trọng hơn, hãy kiểm tra rõ ràng giá trị null và undefined thay vì falsey, điều này sẽ xóa các cặp khóa-giá trị có giá trị false.



-1

Mặc dù _.compactđược tài liệu hóa để sử dụng trong mảng. Nó dường như cũng hoạt động cho các đối tượng. Tôi vừa chạy phần sau trong bảng điều khiển chrome, opera và firefox:

var obj = {first: 1, second: null, third: 3, fourth: function(){return 5}}
undefined
_.compact(obj)

[1, 3, function()]

CẬP NHẬT: Vì mẫu cho biết việc gọi _.compactmột đối tượng sẽ làm rơi các phím và trả về một mảng đã nén.


1
Nhưng nó vẫn trả về một mảng. Chìa khóa bị mất.
Turadg

1
Bạn đúng. Sau đó tôi có xóa câu trả lời của mình không? Hay stackoverflow thích thứ gì khác?
tzvi

2
Tôi không biết một tùy chọn cộng đồng nào đó, nhưng nếu bạn ổn với việc bỏ nó có thể có giá trị ngăn người khác thêm câu trả lời tương tự.
Turadg
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.