2016-04-18 8 views
1

zugegriffen Ich habe ein beliebig tiefes Objekt wie folgt:welche Objekteigenschaften eine Funktion

const objToAccess = { 
    id: 1, 
    name: { 
    first: 'Foo', 
    last: 'Bar' 
    }, 
    address: { 
    street: { 
     name: '987 Walker', 
     roadType: 'Ave' 
    }, 
    zip: '12345' 
    } 
}; 

Ich nenne eine Funktion, die die oben objToAccess als param nimmt. EDIT: Diese Funktion ist eine Blackbox. Ich weiß nicht, wie es aussieht und kann es nicht bearbeiten. Zum Beispiel:

const accessFn = objToAccess => { 
    const a = objToAccess.id; 
    const b = objToAccess.name.first; 
    const c = objToAccess.address; 
}; 

Nachdem diese Funktion aufgerufen wird, möchte ich wissen, auf welche Eigenschaften zugegriffen wurde. Hier ist der Kicker: Wenn auf ein verschachteltes Objekt zugegriffen wurde, möchte ich auch alle untergeordneten Objekte als zugegriffen markieren. Zum Beispiel, nach dem obigen Code ausgeführt wird, würde ich ein Ergebnis mag das wie folgt aussieht:

const propsAccessed = { 
    id: true, 
    name: { 
    first: true, 
    last: false 
    }, 
    address: { 
    street: { 
     name: true, 
     roadType: true 
    }, 
    zip: true 
    } 
}; 

Mein naiver Versuch ist erstellt das propsAccessed Objekt & setzte alles falsch, und dann verwenden Getter (unten). Aber ich kann nicht herausfinden, wie man sie so verwendet, dass alle Kinder markiert werden, wenn nur auf das Elternobjekt zugegriffen wird. Irgendwelche Ideen wären großartig!

const gettedReturnedMutation = { 
    get id() { 
    propsAccessed.id = true; 
    }, 
    get name() { 
    // TODO if just address is accessed, recursively flag all children as true 
    return { 
     get first() { 
     propsAccessed.name.first = true; 
     }, 
     get last() { 
     propsAccessed.name.last = true; 
     } 
    } 
    }, 
    get address() { 
    // TODO if just address is accessed, recursively flag all children as true 
    return { 
     get street() { 
     return { 
      get name() { 
      propsAccessed.address.street.name = true; 
      }, 
      get roadType() { 
      propsAccessed.address.street.roadType = true; 
      } 
     } 
     }, 
     get zip() { 
     propsAccessed.address.zip = true; 
     } 
    } 
    } 
} 
+1

Was ist der Anwendungsfall? Liest ein bisschen wie ein XY-Problem ... – elclanrs

+0

Letztendlich möchte ich 'falsche' Objekte aus dem Objekt entfernen. Realistisch gesehen ist das Objekt ein AST. –

+0

Sie könnten mit Ihrer eigenen Funktion 'access (obj, 'path')' zugreifen und vielleicht den Pfad löschen, der die Kinder los wird. Nicht sicher, warum Sie Kinder kennzeichnen müssen, wenn der Elternteil markiert ist und sowieso entfernt werden muss – elclanrs

Antwort

2

würde ich einen Proxy verwenden:

function isObject(val) { 
    return val === Object(val); 
} 
function detectAccess(obj) { 
    if(!isObject(obj)) return {proxy: obj, accessLog: true}; 
    var subProxies = Object.create(null); 
    var accessLog = Object.create(null); 
    var proxy = new Proxy(obj, { 
    get: function(target, prop, receiver) { 
     if(!accessLog[prop]) { 
     var recur = detectAccess(obj[prop]); 
     accessLog[prop] = recur.accessLog; 
     return subProxies[prop] = recur.proxy; 
     } else { 
     return subProxies[prop]; 
     } 
    } 
    }); 
    return {proxy, accessLog}; 
} 
var {proxy, accessLog} = detectAccess(objToAccess); 
accessFn(proxy); 
accessLog; // {id:true, name:{first:true}, address:{}} 

Die accessLog erzählt, welche Eigenschaften zugegriffen wurde. Wenn der Wert ein Primitiv ist, enthält das Protokoll true, andernfalls enthält es ein Objekt.

Dann, wenn Sie zum Beispiel wissen wollen, ob objToAccess.address.street.name zugegriffen wurde, verwenden

!!(accessLog.address && accessLog.address.street && accessLog.address.name) 

(test for existence of nested object key sehen alle die Eigenschaft Pfad Wiederholung zu vermeiden).

Wenn Sie zu prüfen, dass die gesamte Unterstruktur zugegriffen wurde, wenn eine Eigenschaft des Top-Objekt zugegriffen wurde, benutzen Sie einfach

!!(accessLog.address) 
+0

das ist * fast * richtig. Der einzige Ort, an dem es fehlschlägt, ist der Zugriff auf ein Elternteil UND dessen Kind. Zum Beispiel: 'objToAccess.name' und dann' objToAccess.name.first'.würde 'accessLog.name.first = true' ergeben, aber' last' müsste auch wahr sein. Danke, dass Sie mich in die richtige Richtung gebracht haben! –

+0

@MattK Wenn Sie sowohl '.name.first' als auch' .name.last' als Zugriff verwenden möchten, wenn Sie 'proxy.name' verwenden, müssen Sie nur' accessLog.name' überprüfen. – Oriol

+0

korrigieren Sie mich, wenn ich falsch liege, aber der Zugriff auf '.name.first' +' .name' gibt den gleichen Wert zurück wie der Zugriff auf '.name.first'. Im ersten Fall müsste ich auch '.name.last' als wahr markieren, aber in letzterer sollte' .name.last' falsch sein. –

Verwandte Themen