好的,在浏览完淘汰代码之后,我已经知道发生了什么事情——到编写代码的时候,这还没有记录下来。
这个
value
绑定,当它读取
select
元素,不只是查看元素的DOM值;
it calls
var elementValue = ko.selectExtensions.readValue(element);
现在,什么
selectExtensions
不出所料,是否为
选择
(还有他们的孩子
object
)元素。这就是魔法发生的地方,因为正如代码中的注释所说:
// Normally, SELECT elements and their OPTIONs can only take value of type 'string' (because the values
// are stored on DOM attributes). ko.selectExtensions provides a way for SELECTs/OPTIONs to have values
// that are arbitrary objects. This is very convenient when implementing things like cascading dropdowns.
因此,当值绑定尝试读取
选择
要素
via
selectExtensions.readValue(...)
,将出现以下代码:
case 'select':
return element.selectedIndex >= 0 ? ko.selectExtensions.readValue(element.options[element.selectedIndex]) : undefined;
这基本上是说“好的,找到选定的索引,然后再次使用此函数读取
option
该索引处的元素。所以它读到
选项
元素并得出以下结论:
case 'option':
if (element[hasDomDataExpandoProperty] === true)
return ko.utils.domData.get(element, ko.bindingHandlers.options.optionValueDomDataKey);
return ko.utils.ieVersion <= 7
? (element.getAttributeNode('value') && element.getAttributeNode('value').specified ? element.value : element.text)
: element.value;
啊哈!因此,它存储自己的“has dom data expando property”标志,如果设置了该标志,则不会得到简单的
element.value
但它会进入自己的javascript内存并获取值。这就是它如何返回复杂的JS对象(如我问题示例中的MEAT对象),而不仅仅是
价值
属性字符串。但是,如果没有设置该标志,它实际上只是返回
价值
属性字符串。
这个
writeValue
可以预见,扩展的另一面是,如果复杂数据不是字符串,它会将其写入JS内存,否则它只会将其存储在
价值
的属性字符串
选项
:
switch (ko.utils.tagNameLower(element)) {
case 'option':
if (typeof value === "string") {
ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, undefined);
if (hasDomDataExpandoProperty in element) { // IE <= 8 throws errors if you delete non-existent properties from a DOM node
delete element[hasDomDataExpandoProperty];
}
element.value = value;
}
else {
// Store arbitrary object using DomData
ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, value);
element[hasDomDataExpandoProperty] = true;
// Special treatment of numbers is just for backward compatibility. KO 1.2.1 wrote numerical values to element.value.
element.value = typeof value === "number" ? value : "";
}
break;
所以是的,正如我所怀疑的,knockout在后台存储复杂的数据,但只有当您要求它存储复杂的JS对象时。这就解释了为什么,当您不指定
optionsValue: [someStringValue]
,您的计算函数接收到复杂的用餐对象,而当您指定它时,您只需获得传入的基本字符串—knockout只是从
选项
的
价值
属性。
就我个人而言,我认为这应该被清楚地记录下来,因为这是一个有点出乎意料和特殊的行为,可能会让人困惑,即使这很方便。我将要求他们将其添加到文档中。