【问题标题】:cannot read property push of 'undefined'无法读取“未定义”的属性推送
【发布时间】:2016-09-02 10:32:55
【问题描述】:
app.controller('ctrl', function($scope){
    var socket = io.connect();

    this.messages = [];

    this.sendMessage = function(){
        socket.emit('new message', this.input_message);
        this.input_message = '';
    }

    socket.on('new message', function(data){
        this.messages.push(data);
    });
});

我正在获取套接字发出的数据,但是当我尝试将该数据推送到 messages 数组时,它显示错误 cannot read the property push of undefined。我做错了什么?

【问题讨论】:

  • 请提供fiddle或plunker
  • 请告诉我数据是不是对象。在控制台打印数据
  • @SrinivasAppQube,它不是一个对象。

标签: javascript angularjs sockets scope socket.io


【解决方案1】:

这不起作用,因为您在套接字范围(this.messages.push(data))中调用this,这与控制器范围不同。这就是为什么this.messagesundefined 的原因,因为它是在控制器函数范围内声明的,而不是在套接字回调函数范围内。在 javascript 中,每个函数都有自己的作用域(箭头函数除外)。

建议

app.controller('ctrl', function($scope){
   var ctrlContext = this;
   var socket = io.connect();

   //using the this keyword here means that
   //it's in the controller function scope.
   this.messages = [];

   this.sendMessage = function(){
      socket.emit('new message', this.input_message);
      this.input_message = '';
   }

   socket.on('new message', function(data){
      //inside the callback function we have a different
      //scope, which means that this.messages will be undefined.
      //but by referencing the controller function scope, you
      //are now able to use the messages property set the
      //outer (controller function) scope.
      ctrlContext.messages.push(data);

      //as you stated, you will also have to call $scope.$apply
      //or else the digest cycle will not be triggered.
   });
});

但是,如果您想在套接字回调函数中使用 this 关键字,您可以使用 function.prototype.bind 方法来实现,该方法允许您设置执行函数的上下文。

示例

var person = {
   name: 'John Doe';
}

//Create function and bind to context person    
var changeName = function() {
   this.name = 'Peter Smith';
}.bind(person);

console.log(person); // {name: 'John Doe'}

changeName(person);

console.log(person); // {name: 'Peter Smith'}

对于你的解决方案,它会是这样的:

app.controller('ctrl', function($scope){
   var socket = io.connect();

   this.messages = [];

   var callback = function(data){
      this.messages.push(data);
   }.bind(this);

   socket.on('new message', callback);
});

【讨论】:

  • 我得到了你的解释,但我认为这段代码行不通。您只需将 'this' 替换为 'ctrlContext',
  • 是的,我现在正在更新您如何使用this 密钥
  • 如果我们在 ctrlContext.messages.push(data) 之后使用 $scope.$apply(),那么它会正常工作。无论如何感谢您的帮助
猜你喜欢
  • 2021-03-06
  • 1970-01-01
  • 2017-08-12
  • 1970-01-01
  • 2016-04-22
  • 2020-12-24
相关资源
最近更新 更多