保存淘汰函数时如何处理原型

How to handle prototypes when saving knockout functions

本文关键字:处理 原型 何处理 淘汰 函数 保存      更新时间:2023-09-26

我得到了这个对象Message。在Message上,我有一个原型"toggleLike"。在我保存消息之前,点赞/取消点赞都很有效。然后我得到一个错误:

"TypeError:this.isLikedByMe不是函数"

参照线CCD_ 2(参见下文)。

然而,将"toggleLike"作为对象的属性(函数)很好。

但是为什么原型会导致这个错误呢?

这是我的代码:

Message = function (data) {
    var self = this;
    self.messageID = data.messageID;
    self.messageText = ko.observable(data.messageText);
    self.isLikedByMe = ko.observable(data.isLikedByMe || false);
    // //this works
    // self.toggleLike = function(){
    //     self.isLikedByMe(!self.isLikedByMe());
    // };
    return self;
};
Message.prototype.toggleLike = function () {
    this.isLikedByMe(!this.isLikedByMe());
};
viewModel = function () {
    var self = this;
    self.myMessage = ko.observable( 
        new Message({
            messageID: -1, 
            messageText: 'This is an example' 
        })
    );
    self.likeThisMessage = function (data) {
        data.toggleLike();
        // some more code
    };
    self.sendMessage = function (data) {
        var newmsg = new Message({
                            ID: -1,
                            messageText: self.myMessageText(),
                         });
        self.saveMessage(newmsg);
    };
    self.saveMessage = function (msg) {
        if (msg.ID == -1) {
            //ajax insert
            return $.ajax({
                type: "POST",
                url: serviceRoot + "InsertMessageItem",
                beforeSend: serviceFramework.setModuleHeaders,
                data: msg,
                cache: false
            });
            // handle returndata and update msg.ID to value from db.
        }
        else {
            // update ...
        }
    };
}; // viewModel ends

HTML:

 <ul data-bind="with: myMessage">
    <li>
        <span data-bind="text:messageText"><br/>
        <a href="#self" data-bind="visible: !toggleLike(), click:$root.likeThisMessage">Like</a> 
        <a href="#self" data-bind="visible: toggleLike(),click:$root.likeThisMessage">Unlike</a>
    </li>
</ul>

虽然你的问题不完整,但我想:你在绑定中使用toggleLike,比如

<button data-bind="click: myMessage.toggleLike">Like</button>

问题不在于你使用的是原型上定义的函数,也不在于原型函数调用了构造函数中定义的另一个函数——所有这些都很好。

问题是您使用错误的this执行toggleLike。在Javascript中,您可以从对象"借用"函数,并在完全不同的上下文中执行它们,这意味着它们内部有不同的this

var Mary = function Mary() {
  this.name = 'Mary';
  this.sayName = function sayName() {
    console.log('My name is ' + this.name);
  };
};
var Sue = function Sue() {
  this.name = 'Sue';
};
var mary = new Mary(),
    sue  = new Sue();
mary.sayName.call(sue);
// executes Marys `sayName` with `this` set to `sue`

在Knockout中,这种情况可能会意外发生,通常发生在click绑定中。在上面的绑定示例中:

<!-- we assume that $data here is your viewmodel -->
<button data-bind="click: myMessage.toggleLike">Like</button>

点击时真正发生的事情是Knockout从myMessage"借用"toggleLike,并在this设置为$data的情况下执行它——您的视图模型:

Message.prototype.toggleLike = function () {
  // `this` is now your viewmodel, which does not have `isLikedByMe`
  this.isLikedByMe(!this.isLikedByMe());
};

使用bind来避免这种情况:

<button data-bind="click: myMessage.toggleLike.bind(myMessage)">Like</button>

另一种方法是确保$data是您试图调用函数的对象:

<!-- ko with: myMessage -->
    <button data-bind="click: toggleLike">Like</button>
<!-- /ko -->

同样有效。