在JS或OOP语言中,多态是通过创建不同的类型来创建的。
例如:
class Field {...}
class DropdownField extends Field {
getValue() {
//implementation ....
}
}
假设我有一个包含一些方法的库forms.js:
class Forms {
getFieldsValues() {
let values = [];
for (let f of this.fields) {
values.push(f.getValue());
}
return values;
}
}
这将获取所有的字段值。请注意,库并不关心它是什么字段。
这样,开发人员A创建了库,开发人员B可以创建新字段: AutocompleterField。
他可以在不更改库代码(Forms.js)的情况下在AutocompleterField中添加方法。
如果我在JS中使用函数式编程方法,我如何实现这一点?
如果对象中没有方法,我可以使用case语句,但这违反了原则。如下所示:
if (field.type == 'DropdownField')...
else if (field.type == 'Autocompleter')..
如果开发人员B添加了新类型,他应该更改库代码。
那么,在javascript中有没有什么好方法来解决这个问题,而不是使用面向对象的编程。
我知道Js既不是OOP也不是FP,但不管怎样。
谢谢
发布于 2018-11-13 17:44:38
JavaScript是一种多用途的语言,你当然可以用不同的方法来解决它。当切换到函数式编程时,答案非常简单:使用函数!你的例子的问题是:它是如此的精简,你可以用3行代码做同样的事情:
// getValue :: DOMNode -> String
const getValue = field => field.value;
// readForm :: Array DOMNode -> Array String
const readForm = formFields => formFields.map(getValue);
readForm(Array.from(document.querySelectorAll('input, textarea, select')));
// -> ['Value1', 'Value2', ... 'ValueN']
关键是:Field::getValue()
是如何实现的,它会返回什么?或者更准确地说:DropdownField::getValue()
与AutocompleteField::getValue()
和NumberField::getValue()
有什么不同?它们都只是返回值吗?它们是否返回一对名称和值?他们甚至需要有所不同吗?
因此,问题是,您的Field
类和它们的继承类是因为它们的getValue()
方法的工作方式而不同,还是因为它们具有其他功能而完全不同?例如,文本字段的“自动完成”功能并不(或不应该)与取值的方式相关。
如果您确实需要以不同的方式读取值,您可以实现一个函数,该函数接受{fieldtype: readerFunction}
对的映射/字典/对象/POJO:
/* Library code */
// getTextInputValue :: DOMNode -> String
const getTextInputValue = field => field.value;
// getDropdownValue :: DOMNode -> String
const getDropdownValue = field => field.options[field.selectedIndex].value;
// getTextareaValue :: DOMNode -> String
const getTextareaValue = field => field.textContent;
// readFieldsBy :: {String :: (a -> String)} -> DOMNode -> Array String
readFieldsBy = kv => form => Object.keys(kv).reduce((acc, k) => {
return acc.concat(Array.from(form.querySelectorAll(k)).map(kv[k]));
}, []);
/* Code the library consumer writes */
const readMyForm = readFieldsBy({
'input[type="text"]': getTextInputValue,
'select': getDropdownValue,
'textarea': getTextareaValue
});
readMyForm(document.querySelector('#myform'));
// -> ['Value1', 'Value2', ... 'ValueN']
注意:我故意没有在这里提到像IO monad这样的东西,因为它会使事情变得更加复杂,但您可能想要查看它。
发布于 2018-11-13 17:22:23
在JS或OOP语言中,多态是通过创建不同的类型来创建的。
是。或者更确切地说,通过在不同的对象中实现相同的类型接口。
没有OOP类,我如何使用Javascript多态性
你似乎在这里confuse class
es with types。创建对象根本不需要JS class
语法。
你可以只拥有
const autocompleteField = {
getValue() {
…
}
};
const dropdownField = {
getValue() {
…
}
};
并在您的Forms
实例中使用这两个。
发布于 2018-11-13 17:42:11
取决于你所说的“多态性”是什么意思。Haskell、Scala或PureScript中的类型类提供了所谓的即席多态--这种分派通常是通过将见证对象作为额外的函数参数传递来实现的,然后这些对象将知道如何执行多态功能。
例如,下面的PureScript代码(来自docs)为某些类型提供了show
函数:
class Show a where
show :: a -> String
instance showString :: Show String where
show s = s
instance showBoolean :: Show Boolean where
show true = "true"
show false = "false"
instance showArray :: (Show a) => Show (Array a) where
show xs = "[" <> joinWith ", " (map show xs) <> "]"
example = show [true, false]
它被编译成下面的JS (我把它缩短了):
var Show = function (show) {
this.show = show;
};
var show = function (dict) {
return dict.show;
};
var showString = new Show(function (s) {
return s;
});
var showBoolean = new Show(function (v) {
if (v) {
return "true";
};
if (!v) {
return "false";
};
throw new Error("Failed pattern match at Main line 12, column 1 - line 12, column 37: " + [ v.constructor.name ]);
});
var showArray = function (dictShow) {
return new Show(function (xs) {
return "[" + (Data_String.joinWith(", ")(Data_Functor.map(Data_Functor.functorArray)(show(dictShow))(xs)) + "]");
});
};
var example = show(showArray(showBoolean))([ true, false ]);
这里绝对没有什么魔力,只是一些额外的参数。在“顶部”,您实际上知道具体的类型,您必须传入匹配的具体见证对象。
在您的示例中,您将传递不同形式的类似HasValue
见证的内容。
https://stackoverflow.com/questions/53276744
复制相似问题