Durandal视图模型中的值

时间:2013-04-20 21:02:43

标签: javascript knockout.js requirejs durandal

我有一个令我困惑的问题。我有一个Durandal视图模型定义如下,但this和其他变量和函数的值,因为我逐步完成代码切换和更改。

我评论了下面的内容,因为在代码中移动时更容易显示各种值。

define(['durandal/plugins/router'], function (router) {

    var _outerRouter = router;
    var _outerSelf = this;

    var viewModel = function () {

        var _self = this;
        var _router = router;
        var _searchCriteria = ko.observable('');
        var _searchResults = ko.observableArray([]);
        var _messages = ko.observableArray([]);

        this.searchCriteria = _searchCriteria;
        this.searchResults = _searchResults;
        this.messages = _messages;

        this.search = function () {

            //
            // When called from the view bindings:
            //  > this = viewModel
            //  > _self = _outerSelf = _outerRouter = undefined
            //  > _router = defined
            //
            var that = this;

            //
            // N.B. I set callback context to the viewModel
            //
            var req = $.ajax({
                url: '../api/v1/things',
                dataType: 'json',
                context: this,  
                data: {
                    searchCriteria: this.searchCriteria()
                }
            })
            .done(function (results, status, request) {

                //
                // When called back:
                //  > this = viewModel 
                //  > _self = _outerSelf = _outerRouter = undefined
                //  > _router = defined
                //
                this.searchResults.removeAll();
                this.messages.removeAll();

                //
                // Now when calling:
                //  > doShowResult = showResult = undefined
                //  > this.showResult = defined (have to use 'this')
                //  > displayMultipleResults = defined
                //
                if (results.length == 1) {                    
                    this.showResult(results[0]);
                }
                else {
                    displayMultipleResults(results);
                }
            });

            function displayMultipleResults(results) {

                //
                // When called from ajax.done():
                //  > this = Window ?!?!
                //  > that = viewModel
                //  > _self = _outerSelf = _outerRouter = undefined
                //  > _router = defined
                //
                that.messages.push({ title: 'Found Lots of Things', body: "Please select...blah blah blah", type: 'info' });

                for (var i = 0; i < results.length; i++)
                    that.searchResults.push(results[i]);
            };
        };

        function doShowResult(result) {

            //
            // When called from ajax.done():
            //  > this = viewModel
            //  > _self = _outerSelf = _outerRouter = undefined
            //  > _router = defined
            //
            // and then
            //
            // When called from the view bindings:
            //  > this = the bound searchResult object
            //  > _self = _outerSelf = _outerRouter = undefined
            //  > _router = defined
            //
            _router.navigateTo('show-my-thing');
        }

        this.showResult = doShowResult;
    };

    return viewModel;
});

以下是它必须遵守的观点:

<div>
    <div class="container-narrow">    
        <div class="row-fluid">
            <div class="span12">
                <h3>Search</h3>

                <p>Enter search criteria...</p>

                <div class="control-group">
                    <input type="text" class="input-block-level" placeholder="Criteria" data-bind="value: searchCriteria"/>
                </div>

                <div class="pull-right">
                    <button class="btn btn-primary" data-bind="click: search">
                        <i class="icon-search icon-white"></i> Search
                    </button>
                </div>

            </div>
        </div>
        <br />

        <!-- ko foreach: messages -->
        <div class="row-fluid">
            <div class="alert" data-bind="css: { 'alert-error': type == 'error', 'alert-info': type == 'info', 'alert-success': type == 'success' }">
                <strong data-bind="text: title"></strong> <span data-bind="text: body"></span>
            </div>
        </div>
        <!-- /ko -->

        <!-- ko foreach: searchResults -->
        <div class="row-fluid">
            <div class="span12 well well-small">                
                <div class="span10 search-result">
                    <label>Resut:</label> <span data-bind="{text: $data}"></span><br />
                </div>
                <div class="span2">                    
                    <button class="btn btn-mini btn-success pull-right" data-bind="click: $parent.showResult">
                        View
                    </button>
                </div>
            </div>        
        </div>    
        <!-- /ko -->

    </div>
</div>

我的主要问题是:

  1. 为什么我可以在任何地方访问_router而不是_self(或任何其他变量(_searchCriteria等)?

  2. 执行何时在ajax.done()内并且this的值等于viewModel但是在它进入displaySearchResult this后等于Window对象?

    < / LI>
  3. ajax.done() doShowResultshowResultundefinedthis.showResult工作正常时,肯定this是{{1}然后定义了viewModel

  4. 幸运的是,在这种情况下,我只需要在showResult中导航,并且当我从doShowResult和视图绑定调用时定义_router。但是如果我需要从视图模型中访问一个值 - 如果从视图绑定中调用它将无法使用 - 如何更改绑定或代码以支持它(最好以非hacky方式)?< / p>

  5. 提前感谢任何人可以解决这个问题。

1 个答案:

答案 0 :(得分:4)

'this'关键字在JavaScript中与其他语言的行为非常不同,可见范围的概念也是如此。

在任何给定时间,'this'的值取决于您从中访问它的函数的调用上下文。调用方法有四种不同的方法,每种方法都对“this”有不同的含义。

  1. 作为函数调用(调用命名函数):this = window(即全局对象)。

    function fName() { };
    fName(); // this = window
    
  2. 作为方法调用(调用对象的属性):this =对象

    var o = {};
    o.whatever = function() {};
    o.whatever(); // this = o
    
  3. 作为构造函数调用(使用new关键字):this =新对象

    var Animal = function() { }; // best practice to capitalise the initial letter of function intended to be called as constructor.
    var cat = new Animal(); // this = (what will become cat)
    
  4. 使用apply()和call()方法调用:(这=第一个参数)

    function fName() { };
    var obj1 = {};
    fName.apply(obj1); // this = obj1
    fName.call(obj1); // this = obj1