首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >不带OOP类的Javascript多态性

不带OOP类的Javascript多态性
EN

Stack Overflow用户
提问于 2018-11-13 16:27:45
回答 4查看 1.2K关注 0票数 2

在JS或OOP语言中,多态是通过创建不同的类型来创建的。

例如:

代码语言:javascript
代码运行次数:0
运行
复制
class Field {...}

class DropdownField extends Field {
  getValue() { 
     //implementation ....
  }
}

假设我有一个包含一些方法的库forms.js:

代码语言:javascript
代码运行次数:0
运行
复制
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语句,但这违反了原则。如下所示:

代码语言:javascript
代码运行次数:0
运行
复制
if (field.type == 'DropdownField')...
else if (field.type == 'Autocompleter')..

如果开发人员B添加了新类型,他应该更改库代码。

那么,在javascript中有没有什么好方法来解决这个问题,而不是使用面向对象的编程。

我知道Js既不是OOP也不是FP,但不管怎样。

谢谢

EN

回答 4

Stack Overflow用户

发布于 2018-11-13 17:44:38

JavaScript是一种多用途的语言,你当然可以用不同的方法来解决它。当切换到函数式编程时,答案非常简单:使用函数!你的例子的问题是:它是如此的精简,你可以用3行代码做同样的事情:

代码语言:javascript
代码运行次数:0
运行
复制
// 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:

代码语言:javascript
代码运行次数:0
运行
复制
/* 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这样的东西,因为它会使事情变得更加复杂,但您可能想要查看它。

票数 5
EN

Stack Overflow用户

发布于 2018-11-13 17:22:23

在JS或OOP语言中,多态是通过创建不同的类型来创建的。

是。或者更确切地说,通过在不同的对象中实现相同的类型接口。

没有OOP类,我如何使用Javascript多态性

你似乎在这里confuse classes with types。创建对象根本不需要JS class语法。

你可以只拥有

代码语言:javascript
代码运行次数:0
运行
复制
const autocompleteField = {
    getValue() {
        …
    }
};
const dropdownField = {
    getValue() {
        …
    }
};

并在您的Forms实例中使用这两个。

票数 2
EN

Stack Overflow用户

发布于 2018-11-13 17:42:11

取决于你所说的“多态性”是什么意思。Haskell、Scala或PureScript中的类型类提供了所谓的即席多态--这种分派通常是通过将见证对象作为额外的函数参数传递来实现的,然后这些对象将知道如何执行多态功能。

例如,下面的PureScript代码(来自docs)为某些类型提供了show函数:

代码语言:javascript
代码运行次数:0
运行
复制
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 (我把它缩短了):

代码语言:javascript
代码运行次数:0
运行
复制
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见证的内容。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53276744

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档