草庐IT

javascript - Javascript鸭子打字的例子?

coder 2024-05-17 原文

一些程序员建议不要在 Javascript 中使用伪经典继承,但建议使用鸭子类型并为每个对象提供一组功能。

有没有一个很好的例子来说明如何做到这一点?我在下面有一个示例,但它一次只分配一个功能。我们可以给一个对象分配一整组方法吗,比如我们可以设置一个OceanAnimal的原型(prototype)吗?可以“游泳”、“潜水”和“上升”,LandAnimal 的原型(prototype)对于“run”、“walk”和“jump”,让一个对象从其中一个或两个继承? (所以鱼对象可以继承或获得 OceanAnimal 的功能,而乌龟可以同时获得 OceanAnimalLandAnimal 的功能?)

var yoyo = {
    name: "Yoyo",
    type: "turtle"
}

var simba = {
    name: "Simba",
    type: "lion"
}

var dolphy = {
    name: "Dolphy",
    type: "dolphin"
}

function swim(n) {
    console.log("My name is", this.name, ", I am a", this.type, "and I just swam", n, "feet")
}

function run(n) {
    console.log("My name is", this.name,  ", I am a", this.type, "and I just ran", n, "feet")
}

Object.prototype.respondTo = function(method) {
    return !!(this[method] && (typeof this[method] === "function"));
}

yoyo.swim = swim;
yoyo.swim(10);

dolphy.swim = swim;
dolphy.swim(80);

simba.run = run;
simba.run(200);

yoyo.run = run;
yoyo.run(2);

yoyo.walk = run;
yoyo.walk(1);

console.log(simba.respondTo("swim"));
console.log(simba.respondTo("run"));
console.log(simba.respondTo("walk"));

console.log(yoyo.respondTo("run"));
console.log(yoyo.respondTo("walk"));
console.log(yoyo.respondTo("fly"));

if(dolphy.respondTo("run")) {
    dolphy.run(10);
}

if(dolphy.respondTo("swim")) {
    dolphy.swim(10);
}

输出:
My name is Yoyo , I am a turtle and I just swam 10 feet 
My name is Dolphy , I am a dolphin and I just swam 80 feet 
My name is Simba , I am a lion and I just ran 200 feet 
My name is Yoyo , I am a turtle and I just ran 2 feet 
My name is Yoyo , I am a turtle and I just ran 1 feet 
false 
true 
false 
true 
true 
false 
My name is Dolphy , I am a dolphin and I just swam 10 feet

最佳答案

JavaScript 中的函数是通用的。它们可以用作 subroutines , methods , constructors , namespaces , modules , 以及更多。

人们反对在 JavaScript 中使用伪经典继承的原因是因为它隐藏了 JavaScript 的真正威力。如果不比对象更具表现力,函数也同样具有表现力。 Alonzo Church 已经证明了这一点谁的工作,Lambda Calculus , 是 Turing Complete .

为了直接回答您的问题,我将使用函数来创建 Turtle , 一个 LionDolphin .然后我将演示乌龟是如何成为 OceanAnimal 的。和 LandAnimal , 狮子怎么只有LandAnimal ,以及海豚如何只是 OceanAnimal .最后,我将解释什么是鸭式打字。

首先让我们为 OceanAnimal 创建构造函数。 :

function OceanAnimal() {
    this.swim = function (n) {
        return "I am " + this.name + ", the " + this.type +
               ", and I just swam " + n + " meters.";
    };
}

接下来,我们将为 LandAnimal 创建构造函数。 :
function LandAnimal() {
    this.walk = function (n) {
        return "I am " + this.name + ", the " + this.type +
               ", and I just walked " + n + " meters.";
    };
}

好吧。所以现在让我们为 Turtle 创建构造函数。 :
Turtle.prototype.type = "turtle";

function Turtle(name) {
    this.name = name;
    LandAnimal.call(this);
    OceanAnimal.call(this);
}

这里发生了什么事?好的,我们想要 Turtle从两个 OceanAnimal 继承和 LandAnimal .所以我们调用 LandAnimal.call(this)OceanAnimal.call(this) .通过这种方式,我们使用 OceanAnimalLandAnimal构造函数为 mixins .因此Turtle继承自 OceanAnimalLandAnimal没有真正成为 OceanAnimal 类型或 LandAnimal .

需要注意的另一件事是,我们正在设置 type prototype 上的属性(property)的 Turtle而不是在里面。这是因为 type所有海龟都一样。因此它是共享的。 name另一方面,每只海龟的值可能会有所不同,因此它是在构造函数中设置的。

现在让我们为 Lion 创建类似的构造函数。 :
Lion.prototype.type = "lion";

function Lion(name) {
    this.name = name;
    LandAnimal.call(this);
}

由于LionLandAnimal我们只混入LandAnimal构造函数。

对于 Dolphin 也是如此:
Dolphin.prototype.type = "dolphin";

function Dolphin(name) {
    this.name = name;
    OceanAnimal.call(this);
}

现在我们已经创建了所有的构造函数,让我们创建一只乌龟、一只狮子和一只海豚:
var yoyo = new Turtle("Yoyo");
var simba = new Lion("Simba");
var dolphy = new Dolphin("Dolphy");

Awww,现在让我们释放它们:
alert(yoyo.walk(10));
alert(yoyo.swim(30));   // turtles are faster in the water
alert(simba.walk(20));
alert(dolphy.swim(20));

哈哈。那很有趣。我个人最喜欢yoyo。

好的,那么鸭子打字是什么?我们知道 yoyo 是一个 OceanAnimalLandAnimal .但是,如果我们这样做 yoyo instanceof OceanAnimalyoyo instanceof LandAnimal然后返回 false .什么?
  • 你:愚蠢的 JavaScript。一个 TurtleOceanAnimalLandAnimal !
  • JavaScript: 不是从我站的地方。我只知道这是一个 Turtle .
  • 你:但如果它会游泳,那么它就是 OceanAnimal ,如果它会走路,那么它就是 LandAnimal .

  • 因此,由于 JavaScript 是个大杂烩,我们必须创建自己的测试来检查对象是否为 OceanAnimal。如果是 LandAnimal .

    让我们从 OceanAnimal 开始:
    function isOceanAnimal(object) {
        if (typeof object !== "object") return false;
        if (typeof object.swim !== "function") return false;
        return true;
    }
    

    同样,对于 LandAnimal :
    function isLandAnimal(object) {
        if (typeof object !== "object") return false;
        if (typeof object.walk !== "function") return false;
        return true;
    }
    

    所以现在我们可以使用 isOceanAnimal(yoyo)而不是 yoyo instanceof OceanAnimal , 和 isLandAnimal(yoyo)而不是 yoyo instanceof LandAnimal ;这两个函数都将返回 true为了我们亲爱的悠悠。耶!

    这是一个在 JavaScript 中进行鸭式输入的简单示例。总结:

    When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck.



    相似地:

    When I see an animal which swims like an ocean animal, I call that animal an ocean animal; and when I see an animal which walks like a land animal, I call that animal a land animal.



    编辑:你可以在这里看到上面的代码:http://jsfiddle.net/aaditmshah/X9M4G/

    关于javascript - Javascript鸭子打字的例子?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12762550/

    有关javascript - Javascript鸭子打字的例子?的更多相关文章

    1. ruby - 鸭子输入字符串、符号和数组的优雅方式? - 2

      这是针对我无法破坏的现有公共(public)API,但我确实希望对其进行扩展。目前,该方法采用字符串或符号或任何其他在作为第一个参数传递给send时有意义的内容我想添加发送字符串、符号等列表的功能。我可以只使用is_a吗?数组,但还有其他发送列表的方法,这不是很像ruby​​。我将调用列表中的map,所以第一个倾向是使用respond_to?:map。但是字符串也会响应:map,所以这行不通。 最佳答案 如何将它们全部视为数组?String的行为与仅包含String的Array相同:deffoo(obj,arg)[*arg].eac

    2. ruby-on-rails - 使用 javascript 更改数据方法不会更改 ajax 调用用户的什么方法? - 2

      我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的

    3. ruby-on-rails - 我可以用鸭子类型(duck typing)改进这种方法吗? - 2

      希望我没有误解“ducktyping”的含义,但从我读到的内容来看,这意味着我应该根据对象如何响应方法而不是它是什么类型/类来编写代码。代码如下:defconvert_hash(hash)ifhash.keys.all?{|k|k.is_a?(Integer)}returnhashelsifhash.keys.all?{|k|k.is_a?(Property)}new_hash={}hash.each_pair{|k,v|new_hash[k.id]=v}returnnew_hashelseraise"CustomattributekeysshouldbeID'sorPropertyo

    4. ruby - 在 Mechanize 中使用 JavaScript 单击链接 - 2

      我有这个:AccountSummary我想单击该链接,但在使用link_to时出现错误。我试过:bot.click(page.link_with(:href=>/menu_home/))bot.click(page.link_with(:class=>'top_level_active'))bot.click(page.link_with(:href=>/AccountSummary/))我得到的错误是:NoMethodError:nil:NilClass的未定义方法“[]” 最佳答案 那是一个javascript链接。Mechan

    5. javascript - jQuery 的 jquery-1.10.2.min.map 正在触发 404(未找到) - 2

      我看到有关未找到文件min.map的错误消息:GETjQuery'sjquery-1.10.2.min.mapistriggeringa404(NotFound)截图这是从哪里来的? 最佳答案 如果ChromeDevTools报告.map文件的404(可能是jquery-1.10.2.min.map、jquery.min.map或jquery-2.0.3.min.map,但任何事情都可能发生)首先要知道的是,这仅在使用DevTools时才会请求。您的用户不会遇到此404。现在您可以修复此问题或禁用sourcemap功能。修复:获取文

    6. ruby-on-rails - 我将 Rails3 与 tinymce 一起使用。如何呈现用户关闭浏览器javascript然后输入xss? - 2

      我有一个用Rails3编写的站点。我的帖子模型有一个名为“内容”的文本列。在帖子面板中,html表单使用tinymce将“content”列设置为textarea字段。在首页,因为使用了tinymce,post.html.erb的代码需要用这样的原始方法来实现。.好的,现在如果我关闭浏览器javascript,这个文本区域可以在没有tinymce的情况下输入,也许用户会输入任何xss,比如alert('xss');.我的前台会显示那个警告框。我尝试sanitize(@post.content)在posts_controller中,但sanitize方法将相互过滤tinymce样式。例如

    7. ruby - 使用 Selenium WebDriver 启用/禁用 javascript - 2

      出于某种原因,我必须为Firefox禁用javascript(手动,我们按照提到的步骤执行http://support.mozilla.org/en-US/kb/javascript-settings-for-interactive-web-pages#w_enabling-and-disabling-javascript)。使用Ruby的SeleniumWebDriver如何实现这一点? 最佳答案 是的,这是可能的。而是另一种方式。您首先需要查看链接Selenium::WebDriver::Firefox::Profile#[]=

    8. ruby - Watir-Webdriver 是否支持点击目标为 javascript 的链接? - 2

      我是Ruby和Watir-Webdriver的新手。我有一套用VBScript编写的站点自动化程序,我想将其转换为Ruby/Watir,因为我现在必须支持Firefox。我发现我真的很喜欢Ruby,而且我正在研究Watir,但我已经花了一周时间试图让Webdriver显示我的登录屏幕。该站点以带有“我同意”区域的“警告屏幕”开头。用户点击我同意并显示登录屏幕。我需要单击该区域以显示登录屏幕(这是同一页面,实际上是一个表单,只是隐藏了)。我整天都在用VBScript这样做:objExplorer.Document.GetElementsByTagName("area")(0).click

    9. ruby - 在 YARD 中使用多种方法记录鸭子类型 - 2

      YARD允许我指定方法参数和返回值的类型。因为我真的很喜欢躲避类型,所以很高兴看到YARD还支持通过指定它们必须支持的方法来定义类型。如你所见here,像#first_method,#second_method这样的表达被解释为逻辑析取。这意味着对象需要支持#first_method或#second_method或两者。这不是我需要的。我希望能够指定一个对象需要同时支持我的参数的#first_method和#second_method。有办法指定吗? 最佳答案 没有用于指定复合鸭子类型接口(interface)的惯用语法。也就是说,

    10. 网页设计期末作业,基于HTML+CSS+JavaScript超酷超炫的汽车类企业网站(6页) - 2

      🎉精彩专栏推荐💭文末获取联系✍️作者简介:一个热爱把逻辑思维转变为代码的技术博主💂作者主页:【主页——🚀获取更多优质源码】🎓web前端期末大作业:【📚毕设项目精品实战案例(1000套)】🧡程序员有趣的告白方式:【💌HTML七夕情人节表白网页制作(110套)】🌎超炫酷的Echarts大屏可视化源码:【🔰Echarts大屏展示大数据平台可视化(150套)】🔖HTML+CSS+JS实例代码:【🗂️5000套HTML+CSS+JS实例代码(炫酷代码)继续更新中…】🎁免费且实用的WEB前端学习指南:【📂web前端零基础到高级学习视频教程120G干货分享】🥇关于作者:💬历任研发工程师,技术组长,教学总监;

    随机推荐