【问题标题】:'this' is undefined inside function (not arrow) in object'this' 在对象中的函数(不是箭头)内部未定义
【发布时间】:2017-08-12 18:06:16
【问题描述】:

我可能错了,但我的理解是这样的

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

foo.baz(1);

应该可以正常工作,因为我注意不要将foo.baz 定义为箭头函数,因此baz 中的this 等于foo。当然,当我在控制台上对其进行测试时,它可以正常工作。

现在,我有一个与 React 非常相似的设置,其中 this 出于某种原因未定义。这是代码:

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>                                                                                                                                                 
        );                                                                                                                                                            
    }
}

然后

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>
    );
}                                                                                                                                                                                                                                                                               

我会说它们应该是类似的,但似乎并非如此。当然这不是什么大问题,因为我可以将函数移到对象之外,然后不需要this 引用它,但我很想知道实际发生了什么,因为我无法重现错误.

如果重要的话,我正在用 Babel 转换代码,输出是

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                                                                                                                                       
        });                                                                                                                                                           
    }
 }  

这是在 WebPack 编译器创建的匿名函数中。

【问题讨论】:

  • 您向我们展示了您如何调用foo.baz,但没有向我们展示您如何调用MapRoom.Disabled。当使用普通的function 时,设置this 的函数是调用的,而不是它被定义的地方,所以没有办法回答这个问题。
  • @loganfsmyth 你完全正确,我的错。让我知道现在是否足够。
  • 编译结果不再使用this
  • MapRoom 在反应组件 class?
  • @Sag1v 不,它应该是一个“组件集合”

标签: javascript scope this undefined babeljs


【解决方案1】:

普通function 中的this 值是根据调用函数的方式设置的。对象声明的结构没有影响,只是foo.baz(1);this设置为foo

分解一下,

foo.baz(1);

等价于

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

在这种情况下,_tmp 几乎可以跳过而不是使用 foo

在你的 JSX 案例中

<MapRoom.Disabled />

正在做

declareComponent(MapRoom.Disabled);

该函数只是获取该函数的位置,例如

function declareComponent(someFunc){
    someFunc();
}

到函数被调用时,它只是一个函数,没有obj.someFunc 会导致this 成为obj,所以它最终成为undefined

为了澄清,您的函数被声明为对象的属性这一事实对任何事情都没有影响,它仍然只是一个函数,您需要确保使用正确的this调用该函数如果您有一定的期望值。例如你可以这样做

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

<MapRoomDisabled />

并且由于该函数已与显式上下文绑定,因此它将按您的预期工作。

但是

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

没有什么不同
var obj = {
    prop: null
};
obj.prop = function(){};

var someFunc = function someFunc(){}

var obj = {
    prop: someFunc,
};

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-12-23
    • 2017-03-02
    • 2016-11-30
    • 2018-02-07
    相关资源
    最近更新 更多