无法读取'undefined'的属性推送

时间:2016-09-02 10:32:56

标签: javascript angularjs sockets scope socket.io

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。我做错了什么?

1 个答案:

答案 0 :(得分:2)

这不起作用,因为您在套接字范围(this)中调用this.messages.push(data),这与控制器范围不同。这就是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);
});