Knockout.js中deleteComment函数报错TypeError: this.comments未定义
这个问题的核心是函数执行时this的指向错误,我来帮你拆解并解决:
问题根源
你在删除按钮的点击绑定里写了:
<button data-bind="visible: display(), click: $parent.deleteComment.bind($data, $index)" >Delete Comment</button>
这里的bind($data)把deleteComment函数的this绑定成了当前循环的Comment对象(也就是单条评论的实例),而不是你的AppViewModel。Comment对象里并没有comments这个属性,所以自然会抛出this.comments is undefined的错误。
反观enterComment能正常工作,是因为它的绑定在form上,此时的$data就是AppViewModel实例,bind($data)让函数里的this正确指向了ViewModel,所以能访问到this.comments。
三种可行解决方案
方案1:修正bind的上下文
把按钮绑定里的bind($data)改成bind($parent),让deleteComment的this指向AppViewModel:
<button data-bind="visible: display(), click: $parent.deleteComment.bind($parent, $index)" >Delete Comment</button>
这样在deleteComment函数里,this就会正确指向ViewModel,this.comments就能正常调用了。
方案2:在ViewModel里保存self引用
这是Knockout开发里的经典技巧,在AppViewModel构造函数开头添加var self = this;,之后所有需要访问ViewModel属性的地方都用self代替this,不管函数的this怎么变化,都能拿到正确的ViewModel引用:
var AppViewModel = function (commentList, userList) { var self = this; // 保存ViewModel的引用 this.displayButton = ko.observable(false); this.comments = ko.observableArray(); // ... 其他初始化代码 ... this.deleteComment = function(index){ self.comments.splice(index,1); // 用self代替this } // ... 其他函数 ... };
方案3:使用ES6箭头函数
箭头函数会自动继承外层作用域的this,直接用箭头函数定义deleteComment,就能让函数里的this始终指向AppViewModel:
this.deleteComment = (index) => { this.comments.splice(index,1); }
这种写法更简洁,也不需要操心绑定的上下文问题。
额外小提醒
你的代码里username变量没有用var/let声明,会变成全局变量,建议改成局部变量或者挂载到ViewModel上,比如:
var username; $.ajax({ url: "http://localhost/sem4/recept/UserInfo.php", async: false, dataType: 'json', success: function(data) { username = data.username; } });
这样代码会更规范,也避免全局变量污染。
内容的提问来源于stack exchange,提问作者youssef taoudi

