【问题标题】:Value of this in a Durandal view model这在 Durandal 视图模型中的价值
【发布时间】:2013-04-22 19:54:58
【问题描述】:

我现在有一个令我困惑的问题。我有一个如下定义的 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对象怎么办?

  3. ajax.done() doShowResultshowResultundefinedthis.showResult 工作正常时,如果 thisviewModel 那么 showResult 是否已定义?

  4. 幸运的是,在这种情况下,我只需要在 doShowResult 中导航,并且当我从 ajax.done 和视图绑定调用时定义了 _router。但是,如果我需要从视图模型中访问一个值——如果从视图绑定中调用,这将不可用——我如何更改绑定或代码以支持这一点(最好以非 hacky 方式)?

提前感谢任何人都可以对此有所了解。

【问题讨论】:

    标签: javascript knockout.js requirejs durandal


    【解决方案1】:

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

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

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

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

      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() 方法调用:(this = 第一个参数)

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

    【讨论】:

    • 谢谢你上面非常清楚的解释——它解释了很多,特别是关于第 2 点和第 3 点。但是,我仍然对我如何能够看到 _router 感到困惑但不是 _self 在所有功能中...您也可以帮忙吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-15
    • 2013-10-22
    • 2017-09-20
    • 1970-01-01
    相关资源
    最近更新 更多