2012-08-24 64 views
7

Giả sử tôi muốn tìm kiếm một giá trị, như 'StackOverflow', trong tất cả các biến được khai báo trong window. tôi có thể làm điều đó với mã này:Đệ quy tìm kiếm một giá trị trong biến toàn cục và thuộc tính của nó

function globalSearch(obj, value) { 
    for(var p in obj) 
     if(obj[p] == value) 
      return(p); 
} 
globalSearch(window, 'StackOverflow'); 

Mã này sẽ trả lại tên của một biến có giá trị này (hoặc trả về không có gì). Vì vậy, nếu tôi đã khai báo biến có giá trị 'StackOverflow', nó sẽ tìm thành công biến đó.

Vấn đề của tôi là tôi muốn đi sâu hơn và tìm kiếm qua đối tượng window 's (và các đối tượng lồng nhau riêng của mình) cũng vậy, để đạt được một kết quả như thế này:

var x = 'StackOverflow'      // returns 'x' 
var y = { a : 'StackOverflow' }    // returns 'y.a' 
var z = { a : { b: 'StackOverflow' } }  // returns 'z.a.b' 

Tôi đang gặp vấn đề với kế thừa phương pháp của đối tượng. Có cách nào để làm việc này không?

+0

Điều gì khiến bạn muốn nói đến các vấn đề với các phương pháp được kế thừa? –

Trả lời

11

Tìm kiếm chi tiết nhưng không có chức năng đệ quy gọi

chức năng đệ quy có giới hạn ngăn xếp nội bộ và bộ nhớ chất thải.

tính năng bổ sung thêm

Recursive bảo vệ đối tượng trong hình thức của một mảng tìm kiếm; Nó không sử dụng quá nhiều bộ nhớ của khóa học vì các đối tượng chỉ được lưu trữ dưới dạng tham chiếu.

Trả về true nếu đối tượng khớp với giá trị. Nếu không, nó sẽ trả về '' sẽ khớp với sai.

Mảng sử dụng ký hiệu ngoặc vuông.

function globalSearch(startObject, value) { 
    var stack = [[startObject,'']]; 
    var searched = []; 
    var found = false; 

    var isArray = function(test) { 
     return Object.prototype.toString.call(test) === '[object Array]'; 
    } 

    while(stack.length) { 
     var fromStack = stack.pop(); 
     var obj = fromStack[0]; 
     var address = fromStack[1]; 

     if(typeof obj == typeof value && obj == value) { 
      var found = address; 
      break; 
     }else if(typeof obj == "object" && searched.indexOf(obj) == -1){ 
      if (isArray(obj)) { 
       var prefix = '['; 
       var postfix = ']'; 
      }else { 
       var prefix = '.'; 
       var postfix = ''; 
      } 
      for(i in obj) { 
       stack.push([ obj[i], address + prefix + i + postfix ]); 
      } 
      searched.push(obj); 
     } 
    } 
    return found == '' ? true : found; 
} 

vấn đề

Nếu không đi qua các tên biến ban đầu vào chức năng, chúng tôi không thể trả lại tên biến đầy đủ ngay từ đầu. Tôi không thể nghĩ ra một giải pháp và tôi sẽ ngạc nhiên nếu có một.

Tên biến có khoảng trắng hợp lệ làm khóa cho đối tượng, cũng như các tên biến không hợp lệ khác, điều đó chỉ có nghĩa là giá trị phải được xử lý bằng dấu ngoặc nhọn. Có một vài giải pháp mà tôi có thể nghĩ đến. Regex kiểm tra từng tên biến để đảm bảo tên biến hợp lệ và sử dụng ký pháp ngoặc vuông nếu không. Vấn đề quan trọng với điều này là reg-ex là một trang dài. Ngoài ra, chúng tôi chỉ có thể sử dụng dấu ngoặc nhọn nhưng điều này không thực sự đúng với câu hỏi ban đầu của OP.

Cuộc gọi indexOf trên mảng 'đã tìm kiếm' có thể hơi nặng trên các đối tượng rất lớn nhưng tôi chưa thể nghĩ ra một giải pháp thay thế.

Cải tiến

Ngoài dọn dẹp mã một chút, nó cũng sẽ được tốt đẹp nếu chức năng trả lại một mảng các trận đấu. Điều này cũng làm tăng một vấn đề khác trong đó mảng được trả về sẽ không chứa tham chiếu đến các đối tượng đệ quy. Có lẽ chức năng có thể chấp nhận tham số cấu hình định dạng kết quả.

+0

Chạy trên hầu như bất kỳ trang nào trong bảng điều khiển firebug, tôi nhận được "Thao tác không an toàn". Tôi đang rối tung xung quanh với một số đề án bắt lỗi, nhưng tôi không chắc tôi sẽ tìm thấy bất cứ điều gì tốt, đủ để thêm vào đây. Có thể ai đó khác có thể cải thiện được điều này? – eternalnewb

4

Điều này sẽ hiệu quả. Nó sử dụng đệ quy để đạt được kết quả.

function globalSearch(obj, value) { 
    for(var p in obj) 
     if(obj[p] == value){ 
      return(p); 
     }else if(typeof obj[p] == "object" && obj[p] != obj){ 
      var te = globalSearch(obj[p], value); 
      if(te!=false){ return p + "." + te } 
     } 
    return false; 
} 
0

Làm cho giải pháp của bạn đệ quy. Nếu bạn có một đối tượng, hãy gọi lại hàm của bạn.

function globalSearch(obj, value) { 
    for(var p in obj) { 
     if (obj[p] == value) { 
      return(p); 
     } else if (typeof obj[p] === "object") { 
      var recursiveCheck= globalSearch(obj[p], value); 
      if (recursiveCheck) { 
       return p + "." + recursiveCheck; 
      } 
     } 
    } 
} 
globalSearch(window, 'StackOverflow'); 

Tôi đặt cược hầu hết các trình duyệt sẽ nhấn cảnh báo quá nhiều vòng lặp.

+2

Lưu ý rằng chức năng của bạn gặp khó khăn khi sử dụng 'window' làm' obj' của bạn. – Ravan

+0

@Ravan: xem câu trả lời của tôi, câu trả lời cho điều đó. – JCOC611

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