我有一个令我困惑的问题。我有一个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>
我的主要问题是:
为什么我可以在任何地方访问_router
而不是_self
(或任何其他变量(_searchCriteria等)?
执行何时在ajax.done()
内并且this
的值等于viewModel但是在它进入displaySearchResult this
后等于Window对象?
当ajax.done()
doShowResult
和showResult
内undefined
但this.showResult
工作正常时,肯定this
是{{1}然后定义了viewModel
?
幸运的是,在这种情况下,我只需要在showResult
中导航,并且当我从doShowResult
和视图绑定调用时定义_router
。但是如果我需要从视图模型中访问一个值 - 如果从视图绑定中调用它将无法使用 - 如何更改绑定或代码以支持它(最好以非hacky方式)?< / p>
提前感谢任何人可以解决这个问题。
答案 0 :(得分:4)
'this'关键字在JavaScript中与其他语言的行为非常不同,可见范围的概念也是如此。
在任何给定时间,'this'的值取决于您从中访问它的函数的调用上下文。调用方法有四种不同的方法,每种方法都对“this”有不同的含义。
作为函数调用(调用命名函数):this = window(即全局对象)。
function fName() { };
fName(); // this = window
作为方法调用(调用对象的属性):this =对象
var o = {};
o.whatever = function() {};
o.whatever(); // this = o
作为构造函数调用(使用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)
使用apply()和call()方法调用:(这=第一个参数)
function fName() { };
var obj1 = {};
fName.apply(obj1); // this = obj1
fName.call(obj1); // this = obj1