2017-08-12 2 views
1

Je peux me tromper, mais je crois comprendre que ce« ce » est pas défini dans la fonction (non flèche) dans l'objet

var foo = {                                       
    'bar': x => x + 1,                                     
    'baz': function(y){ return this.bar(y); }                               
};                                          

foo.baz(1); 

devrait fonctionner correctement puisque je pris soin de ne pas définir foo.baz comme une fonction de flèche et ainsi this à l'intérieur baz est égal à foo. Bien sûr, quand je le teste sur une console, ça fonctionne comme je le pensais.

Maintenant, j'ai une configuration très similaire avec React dans lequel this est indéfini pour une raison quelconque. Voici le code:

const MapRoom = {                                      
    'getStyleFromCoords': coords => {                                 
     return { // account for borders                                
      'left': coords[0] + 1,                                
      'top': coords[1] + 1,                                
      'width': (coords[2] - coords[0]) - 2,                           
      'height':(props.coords[3] - props.coords[1]) - 2,                           
     };                                        
    },                                         
    'Disabled': function(props){                                  
     console.log('this', this); // undefined                                  
     const style = this.getStyleFromCoords(props.coords); // error                           

     return (                                      
      <div                                      
       className="room-selected"                                
       style={style}                                   
       title={props.number}                                  
       ></div>                                     
     );                                        
    } 
} 

puis

renderRooms(){                                       
    // stuff                        

    return this.state.coords.map((coords, index) => {                             
     // more stuff 
     if(disabled){                                         
      return (                                          
       <MapRoom.Disabled                                       
        key={roomNumber}                                  
        number={roomNumber}                                      
        coords={coords}                                  
        />                                     
      );                                       
     } else if(...){} 
    }); 
} 

render(){ 
    return (
     <stuff> 
      {this.renderRooms()} 
     </stuff> 
    ); 
}                                                                    

Je dirais qu'ils devraient être analogue, mais il semble que ce n'est pas le cas. Bien sûr, cela ne pose pas beaucoup de problème car je peux simplement déplacer la fonction hors de l'objet et il n'y a pas besoin de this pour le référencer, mais je suis curieux de savoir ce qui se passe réellement car je n'arrive pas à reproduire l'erreur.

Dans le cas où il importe, je suis transpiling le code avec Babel et la sortie est

var MapRoom = {                                      
    'getStyleFromCoords': function getStyleFromCoords(coords) {                          
     return { // account for borders                                
      'left': coords[0] + 1,                                
      'top': coords[1] + 1,                                
      'width': coords[2] - coords[0] - 2,                           
      'height': coords[3] - coords[1] - 2                           
     };                                        
    },                                         
    'Disabled': function Disabled(props) {                                
     console.log('this', this);                                  
     var style = this.getStyleFromCoords(props.coords);                             

     return __WEBPACK_IMPORTED_MODULE_0_react___default.a.createElement('div', {                     
      className: 'room-selected',                                
      style: style,                                    
      title: props.number                                  
     });                                       
    } 
} 

C'est à l'intérieur d'une fonction anonyme créée par le compilateur WebPack.

+2

Vous nous a montré comment vous appeliez 'foo.baz', mais pas ce qui est appel à' MapRoom .Disabled'. Lorsque vous utilisez une 'fonction' normale, c'est comment la fonction est appelée _called_ qui définit' this', pas où elle a été définie, donc il n'y a aucun moyen de répondre à cela. – loganfsmyth

+0

@loganfsmyth vous avez totalement raison, mon mauvais. Dites-moi si c'est suffisant maintenant. – cronos2

+0

Le résultat de compilation n'utilise plus 'this'. – melpomene

Répondre

1

La valeur this dans un function normal est définie en fonction de l'appel de la fonction. La structure de la façon dont l'objet est déclaré n'a aucun effet, c'est juste que foo.baz(1); définit this à foo.

Pour le briser,

foo.baz(1); 

est équivalent à

let _tmp = foo; 
_tmp.baz.call(_tmp, 1); 

où, dans ce cas, le _tmp pourrait être à peu près ignoré en place à l'aide d'un peu foo.

Dans votre cas JSX

<MapRoom.Disabled /> 

est en train de faire

declareComponent(MapRoom.Disabled); 

où cette fonction obtient juste la fonction, par exemple

function declareComponent(someFunc){ 
    someFunc(); 
} 

Au moment où la fonction est appelée, elle est juste une fonction, il n'y a pas obj.someFunc qui causerait this d'être obj, il finit par être undefined. Pour clarifier, le fait que votre fonction soit déclarée en tant que propriété sur un objet n'a aucun effet sur quoi que ce soit, c'est toujours une fonction et c'est à vous de vous assurer que la fonction est appelée avec la valeur this appropriée si vous avez certaines attentes.Par exemple vous pouvez faire

const MapRoomDisabled = MapRoom.Disabled.bind(MapRoom); 

<MapRoomDisabled /> 

et puisque la fonction a été liée avec un contexte explicite, cela fonctionnerait comme prévu.

Mais

var obj = { 
    prop: function(){} 
}; 

est pas différent de

var obj = { 
    prop: null 
}; 
obj.prop = function(){}; 

ou

var someFunc = function someFunc(){} 

var obj = { 
    prop: someFunc, 
};