在带有敲除和杜兰达尔的揭示原型模式中对“这个”的混淆

Confusion over "this" in the revealing prototype pattern with knockout and durandal

本文关键字:模式 这个 原型 杜兰达      更新时间:2023-09-26

我正在尝试为我的应用程序制作基本视图模型,但我正在努力访问基本视图模型的上下文。

这是我的基本视图模型:

define(["config", 'services/logger'], function (config, logger) {
    'use strict';
    var
    app = require('durandal/app'),
    baseViewModel = function () {
        this.items = ko.observableArray();
        this.title = ko.observable();
        this.selectedItem = ko.observable();
    };
    baseViewModel.prototype = (function () {
        var
        populateCollection = function (initialData, model) {
            var self = this;
            if (_.isEmpty(self.items())) {
                ko.utils.arrayForEach(initialData, function (item) {
                    // self here works for all extending modules such as users
                    self.items.push(new model(item));
                });
            }
        },
        deleteItem = function (item) {
            // "this" here same as prototype gives me window object :(
            // so removing never happes
            this.items.remove(item);
            logger.log(config.messages.userMessages.confirmDeleted(item.Name()), {}, '', true);
        },
        confirmDelete = function (item) {
            var
            userMessage = config.messages.userMessages.confirmDelete(item.Type(), item.Name()),
            negation = config.confirmationModalOptions.negation,
            affirmation = config.confirmationModalOptions.affirmation;
            app.showMessage(userMessage, 'Deleting ' + item.Type(), [affirmation, negation]).then(
                function (dialogResult) {
                    dialogResult === affirmation ? deleteItem(item) : false;
                });
        };
        return {
            populateCollection: populateCollection,
            confirmDelete: confirmDelete,
            deleteItem: deleteItem
        }
    })();
    return baseViewModel;
});

我使用这个非工作的东西的一个例子是:

define(['services/logger', 'models/user', 'viewmodels/baseviewmodel', 'services/dataservice'], function (logger, user, baseviewmodel, dataservice) {
    var
    users = new baseviewmodel();
    users.title('Users')
    users.searchTerm = ko.observable().extend({ persist: users.title() + '-searchterm' });
    users.activate = function () {
        this.populateCollection(dataservice.getUsers, user.model);
    }
    return users;
});

项目确实使用 populateCollection 正确填充。 confirmDelete也会在模板中正确绑定,这可能是由于不需要上下文但是deleteItem需要上下文,以便它可以访问items并调用remove

如何正确访问this作为baseViewModel的上下文 所以我可以用这种模式在我的方法中轻松引用它?

非常感谢

编辑:看起来this在 deleteItem 中没有正确绑定,因为它是在 confirmDelete 内部的回调中调用的。因此,请在原始模型上尝试此代码段

    confirmDelete = function (item) {
        var self=this,
        userMessage = config.messages.userMessages.confirmDelete(item.Type(), item.Name()),
        negation = config.confirmationModalOptions.negation,
        affirmation = config.confirmationModalOptions.affirmation;
        app.showMessage(userMessage, 'Deleting ' + item.Type(), [affirmation, negation]).then(
            function (dialogResult) {
                dialogResult === affirmation ? self.deleteItem.call(self,item) : false;
            });
    };

奥尔,我的另一个解决方案。

我以前从未使用过"揭示原型模式",所以这里是如何在不坚持我们都不理解的模式的情况下做到这一点:)

我将所有内容声明为视图模型的属性并使用var self = this,这样我的所有代码都非常明确。这是您的基本视图模型,已重写。如果所有视图模型逻辑都封装在视图模型中,并且视图模型在构造函数/函数定义中声明其依赖项,这通常很有帮助。

baseViewModel = function (dataService,userModel) {
    var self = this;
    self.items = ko.observableArray();
    self.title = ko.observable();
    self.searchTerm = ko.observable().extend({ persist: self.title() + '-searchterm' });
    self.selectedItem = ko.observable();
    self.populateCollection = function (initialData, model) {
        if (_.isEmpty(self.items())) {
            ko.utils.arrayForEach(initialData, function (item) {
                // self here works for all extending modules such as users
                self.items.push(new model(item));
            });
        }
    };
    self.activate = function () {
        this.populateCollection(dataservice.getUsers, userModel);
    }
    self.deleteItem = function (item) {
        // "this" here same as prototype gives me window object :(
        // so removing never happes
        self.items.remove(item);
        logger.log(config.messages.userMessages.confirmDeleted(item.Name()), {}, '', true);
    };
    self.confirmDelete = function (item) {
        var
        userMessage = config.messages.userMessages.confirmDelete(item.Type(), item.Name()),
        negation = config.confirmationModalOptions.negation,
        affirmation = config.confirmationModalOptions.affirmation;
        app.showMessage(userMessage, 'Deleting ' + item.Type(), [affirmation, negation]).then(
            function (dialogResult) {
                dialogResult === affirmation ? self.deleteItem(item) : false;
            });
    };
};

请注意,因为我还将依赖项移动到视图模型构造函数中,所以现在您的初始化代码如下所示:

define(['services/logger', 'models/user', 'viewmodels/baseviewmodel', 'services/dataservice'], function (logger, user, baseviewmodel, dataservice) {
    var users = new baseviewmodel(dataservice,user.model);
    users.title('Users')
    return users;
});