2013-02-12 38 views
30

Có cách nào để có được Underscore.js extend chức năng:Đệ quy/mở rộng/phân bổ sâu trong Underscore.js?

Sao chép tất cả các tài sản trong các đối tượng nguồn giao cho đối tượng đích, và trả lại đối tượng đích. Theo thứ tự, để nguồn cuối cùng sẽ ghi đè các thuộc tính có cùng tên trong các đối số trước đó là .

... để hoạt động đệ quy?

Trên thực tế, query tài sản trong creditOperation sẽ hoàn toàn ghi đè query tài sản quy định tại baseOperation:

var url = require('url') 
    , _ = require('underscore'), 
    , baseOperation = { 
     host: 'gateway.skebby.it', 
     pathname: 'api/send/smseasy/advanced/http.php', 
     protocol: 'https', 
     query: { 
      'username': 'foo', 
      'password': 'bar', 
     } 
    }; 

var creditOperation = _.extend(baseOperation, { 
    query: { 
     'method': 'baz' 
    } 
}); 

console.log(url.format(creditOperation)); 

Tôi muốn để có được này creditOperation:

{ 
    host: 'gateway.skebby.it', 
    pathname: 'api/send/smseasy/advanced/http.php', 
    protocol: 'https', 
    query: { 
     'username': 'foo', 
     'password': 'bar', 
     'method': 'baz' 
    } 
} 
+1

Bạn có thể thêm các từ "sâu" và "chỉ định" vào tiêu đề của mình để chuỗi có thể dễ dàng tìm thấy qua Google hay không. Giống như "Mở rộng/đệ quy sâu/gán trong Underscore.js?" –

Trả lời

20

Không, Underscore will not contain a deep extend vì nó quá phức tạp để đối phó với các loại đối tượng khác nhau. Thay vào đó, người dùng được khuyến khích thực hiện các giải pháp của riêng mình với sự hỗ trợ cho những gì họ cần.

Trong trường hợp của bạn nó chỉ đối tượng đơn giản, vì vậy một thực hiện khá đơn giản:

_.deepObjectExtend = function(target, source) { 
    for (var prop in source) 
     if (prop in target) 
      _.deepObjectExtend(target[prop], source[prop]); 
     else 
      target[prop] = source[prop]; 
    return target; 
} 
+6

Dường như điều này sẽ ném một ngoại lệ như khi nó chạm vào một thuộc tính không phải là một đối tượng. Bạn cần phải xác minh rằng cả hai [prop] và nguồn [prop] đích đều là các đối tượng trước khi bạn cố gắng recurse. Có lẽ một cái gì đó như 'if (prop trong mục tiêu && typeof (mục tiêu [prop]) == 'đối tượng' && typeof (nguồn [prop]) == 'đối tượng')' cho dòng thứ ba thay thế. – wizzard

+0

Vâng, tôi mong đợi chức năng 'mở rộng' này chỉ mở rộng (mở rộng?) Đối tượng, không ghi đè lên bất kỳ thuộc tính nào trong chúng (mô tả chỉ * đối tượng thuần *). Nếu bạn muốn điều đó, 'if (typeof target [prop] == 'object')' là đủ. – Bergi

+1

Tôi không chắc chắn làm thế nào có hai đối tượng với cùng một thuộc tính làm cho chúng _not_ đối tượng đơn giản. Hàm này có ích hơn khoảng 5x nếu nó xử lý các đối tượng có cùng thuộc tính (và nhiều hơn nữa trong tinh thần của _.extend). Ngoài ra, chỉ kiểm tra mục tiêu [prop] là một đối tượng sẽ vẫn cho kết quả bất ngờ (wildly) trong trường hợp prop nguồn không phải là một đối tượng và prop mục tiêu là: http://jsfiddle.net/wizzard/HY4yQ/ Phải thừa nhận rằng, bạn có thể muốn suy nghĩ thêm về chức năng này nếu bạn có trường hợp như vậy. – wizzard

36

Với Lodash (ngã ba của dấu gạch dưới) u có thể. Phương thức _.extend của Lodash chấp nhận tham số thứ ba (hoặc cao hơn) là một hàm, nhận các giá trị (cũ và mới); Vì vậy, bạn có thể làm điều gì đó như sau:

var deep = function(a, b) { 
    return _.isObject(a) && _.isObject(b) ? _.extend(a, b, deep) : b; 
}; 

var a = {a:{b:{c:1}}}, 
    b = {a:{b:{z:1}}}; 

_.extend(a,b,deep); 

upd. Như Paolo Moretti nói trong ý kiến, có chức năng tương tự trong lodash gọi _.merge:

_.merge(a,b); 
+12

Bạn cũng có thể sử dụng ['_.merge'] (http://lodash.com/docs#merge): _Recursively kết hợp các thuộc tính đếm được của riêng đối tượng nguồn (s), không phân giải thành undefined vào đối tượng đích_. –

+0

điều này không trả lời câu hỏi – dovidweisz

+3

@wapsee, ngược lại, tôi nghĩ đây là câu trả lời hữu ích nhất. – weaver

19

jQuery có chức năng extend(), mà làm điều tương tự như đối gạch dưới nó, nhưng cũng có một sâu luận cho phép nó kết hợp một cách đệ quy như bạn mong muốn:

var creditOperation = $.extend(true, baseOperation, { 
    query: { 
     'method': 'baz' 
    } 
}); 

Hoặc, nếu bạn không muốn ghi đè lên baseOperation:

var creditOperation = $.extend(true, {}, baseOperation, { 
    query: { 
     'method': 'baz' 
    } 
}); 
+0

Cảm ơn bạn vì điều này, tốt nhất là sử dụng hơn viết của riêng bạn, dù sao trong nhiều trường hợp jquery được sử dụng trong dự án. – Kostanos

+3

Đây là những gì nhiều người thực sự muốn khi họ tìm thấy trang này :) –

+0

câu hỏi thứ hai là câu trả lời triệu đô la !!! Tôi chỉ có thể cung cấp cho bạn +1 :) – Gogol

6

phiên bản Stand-alone của Bergi của sâu mở rộng, bao gồm các bản sửa lỗi cho khi một giá trị là một chuỗi thay vì một đối tượng. Cũng được vá để được nghiêm ngặt hơn.

function deepObjectExtend (target, source) { 
    for (var prop in source) { 
     if (source.hasOwnProperty(prop)) { 
      if (target[prop] && typeof source[prop] === 'object') { 
       deepObjectExtend(target[prop], source[prop]); 
      } 
      else { 
       target[prop] = source[prop]; 
      } 
     } 
    } 
    return target; 
} 
2

Kurt Milam đã xuất bản mixin that adds a deepExtend method to underscore.js. Nó thậm chí giao dịch với các biểu thức thông thường (nếu bạn muốn). Trích từ tài liệu:

Kết hợp bằng dấu gạch dưới.js: _.mixin({deepExtend: deepExtend});

Gọi nó như thế này: var myObj = _.deepExtend(grandparent, child, grandchild, greatgrandchild)

Ghi chú: Giữ nó khô.

Chức năng này đặc biệt hữu ích nếu bạn đang làm việc với tài liệu cấu hình JSON. Nó cho phép bạn tạo tài liệu cấu hình mặc định với cài đặt phổ biến nhất, sau đó ghi đè cài đặt cho các trường hợp cụ thể. Nó chấp nhận bất kỳ số đối tượng nào như các đối số , cho phép bạn kiểm soát chi tiết hơn cấu hình phân cấp của mình theo cấu trúc phân cấp .

0

mở rộng gạch dưới() không mở rộng sâu; như một vấn đề của thực tế, không có chức năng trong gạch dưới mà có thể mở rộng sâu.

Bạn có thể sử dụng số merge của lodash cho điều đó.

Các vấn đề liên quan