2017-10-19 52 views
1

Si je comprends bien, object.hasOwnProperty() devrait retourner false sur les propriétés héritées de la classe parente. Toutefois, le code suivant renvoie true sur les propriétés propres et héritées.Script de type: object.hasOwnProperty() indique true sur la propriété héritée. Pourquoi?

Est-ce que ma compréhension/code est incorrect ou est hasOwnPropery() incorrect? Si c'est moi, comment distinguer les propriétés propres des propriétés héritées?

Modifier: J'ai ajouté mon cas d'utilisation à l'exemple de code.

Je m'attendrais à ce que le fromDb() de l'enfant s'occupe seulement de ses propres propriétés, à la place, il substitue les propriétés définies par le fromDb() du parent.

class Parent { 
    parentProp = ''; 
    fromDb(row: {}) { 
     for (const key of Object.keys(row)) { 
      if (this.hasOwnProperty(key)) { 
       if (key === 'parentProp') { 
        // Do some required data cleansing 
        this[key] = row[key].toUpperCase() 
       } else { 
        this[key] = row[key]; 
       } 
      } 
     }; 
     return this; 
    } 
} 

class Child extends Parent { 
    childProp = ''; 
    fromDb(row: {}) { 
     super.fromDb(row); 
     for (const key of Object.keys(row)) { 
      if (this.hasOwnProperty(key)) { 
       this[key] = row[key]; 
      } 
     }; 
     return this; 
    } 
} 

let row = { 
    parentProp: 'parent', 
    childProp: 'child', 
} 

let childObj = new Child().fromDb(row); 
console.log(childObj); 

Console:

Child: 
    childProp: "child" 
    parentProp: "parent" 

Répondre

2

Dans le code généré extends, les propriétés sont copiés dans la sous-classe comme ceci:

function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; 

Ce qui signifie que votre sous-classe (d) est donné sa propre propriété.

Ceci est en fait pas différent d'utiliser l'héritage JavaScript simple:

function Parent() { 
    this.parentProp = `I'm defined by Parent`; 
} 

function Child() { 
    Parent.call(this); 
    this.childProp = `I'm defined by Child`; 
} 

let childObj = new Child(); 

for (const key of Object.keys(childObj)) { 
    console.log(key, childObj.hasOwnProperty(key)); 
} 

Si vous nous donnez une direction sur ce que vous devez réaliser, je suis sûr que nous allons trouver un mécanisme approprié pour vous qui surmonter cet obstacle.

Utilisation de cas spécifiques

Pour votre cas d'utilisation spécifique, vous pouvez définir le précédent pour qui « gagne » par où vous appelez la superclasse.

Pour obtenir la sortie

childProp: "child" 
parentProp: "PARENT" 

Laissez le parent "deuxième", plutôt que "d'abord":

class Child extends Parent { 
    childProp = ''; 
    fromDb(row: {}) { 
     for (const key of Object.keys(row)) { 
      if (this.hasOwnProperty(key)) { 
       this[key] = row[key]; 
      } 
     }; 

     super.fromDb(row); // <-- last update wins 
     return this; 
    } 
} 

Super Dynamic Property Stuff

Cela exclut dynamiquement les clés mères à partir des clés enfant et enfant du parent ... ajouter console.log déclarations pour voir les internes ...

class Parent { 
    parentProp = ''; 
    fromDb(row: {}) { 

     const ownKeys = Object.keys(new Parent()); 

     for (const key of Object.keys(row)) { 
      if (ownKeys.indexOf(key) > -1) { 
       if (key === 'parentProp') { 
        // Do some required data cleansing 
        this[key] = row[key].toUpperCase() 
       } else { 
        this[key] = row[key]; 
       } 
      } 
     }; 
     return this; 
    } 
} 

class Child extends Parent { 
    childProp = ''; 
    fromDb(row: {}) { 
     super.fromDb(row); 

     const ownKeys = this.getKeys(); 

     for (const key of Object.keys(row)) { 
      if (ownKeys.indexOf(key) > -1) { 
       this[key] = row[key]; 
      } 
     }; 
     return this; 
    } 

    getKeys() { 
     const childKeys = Object.keys(this); 
     const parentKeys = Object.keys(new Parent()); 

     return childKeys.filter(function(el) { 
      return parentKeys.indexOf(el) < 0; 
     }); 
    } 
} 

let row = { 
    parentProp: 'parent', 
    childProp: 'child', 
} 

let childObj = new Child().fromDb(row); 
console.log(childObj); 
+0

J'ai modifié la question pour inclure mon cas d'utilisation. – passerby

+0

J'ai ajouté quelques détails pour ce cas d'utilisation spécifique. Si vous avez besoin d'être plus sélectif, vous devrez créer une carte de propriétés pour que l'enfant regarde la carte, plutôt que ses propres clés (ie "si la propriété est dans ma carte, je la changerai, sinon je ne le ferai pas"). – Fenton

+0

Il semble que la copie ait lieu dans les deux sens. Quand j'ajoute 'console.log (Object.keys (this))' au 'fromDb()' du Parent, il montre aussi les propriétés de l'Enfant lorsqu'il est appelé par 'super.fromDb (row)'. Je n'ai jamais réalisé cet effet du sucre syntaxique. Naive me ... – passerby

0

Les classes ne sont que du sucre syntaxique pour la bonne vieille syntaxe de la fonction constructeur. Les propriétés définies dans la classe sont toujours des propriétés d'instance compilées aux valeurs définies dans la fonction constructeur:

function Parent() { 
    this.parentProp = "I'm defined by Parent"; 
} 

La propriété ne vient pas du prototype, c'est une propriété d'instance définie sur this dans le constructeur. Seules les méthodes sont partagées sur le prototype. Si vous voulez des propriétés partagées, elles doivent être déclarées static; mais alors ils sont une propriété de classe et pas sur le prototype non plus.

+0

Je pense que je dois ajuster ma façon de penser à OO ... – passerby