一些程序员建议不要在 Javascript 中使用伪经典继承,但建议使用鸭子类型并为每个对象提供一组功能。
有没有一个很好的例子来说明如何做到这一点?我在下面有一个示例,但它一次只分配一个功能。我们可以给一个对象分配一整组方法吗,比如我们可以设置一个OceanAnimal的原型(prototype)吗?可以“游泳”、“潜水”和“上升”,LandAnimal 的原型(prototype)对于“run”、“walk”和“jump”,让一个对象从其中一个或两个继承? (所以鱼对象可以继承或获得 OceanAnimal 的功能,而乌龟可以同时获得 OceanAnimal 和 LandAnimal 的功能?)
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 , 一个 Lion和 Dolphin .然后我将演示乌龟是如何成为 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) .通过这种方式,我们使用 OceanAnimal和 LandAnimal构造函数为 mixins .因此Turtle继承自 OceanAnimal和 LandAnimal没有真正成为 OceanAnimal 类型或 LandAnimal .type prototype 上的属性(property)的 Turtle而不是在里面。这是因为 type所有海龟都一样。因此它是共享的。 name另一方面,每只海龟的值可能会有所不同,因此它是在构造函数中设置的。Lion 创建类似的构造函数。 :Lion.prototype.type = "lion";
function Lion(name) {
this.name = name;
LandAnimal.call(this);
}
Lion是 LandAnimal我们只混入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");
alert(yoyo.walk(10));
alert(yoyo.swim(30)); // turtles are faster in the water
alert(simba.walk(20));
alert(dolphy.swim(20));
OceanAnimal和 LandAnimal .但是,如果我们这样做 yoyo instanceof OceanAnimal或 yoyo instanceof LandAnimal然后返回 false .什么?Turtle是 OceanAnimal和 LandAnimal ! Turtle . OceanAnimal ,如果它会走路,那么它就是 LandAnimal . 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为了我们亲爱的悠悠。耶!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.
关于javascript - Javascript鸭子打字的例子?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12762550/
这是针对我无法破坏的现有公共(public)API,但我确实希望对其进行扩展。目前,该方法采用字符串或符号或任何其他在作为第一个参数传递给send时有意义的内容我想添加发送字符串、符号等列表的功能。我可以只使用is_a吗?数组,但还有其他发送列表的方法,这不是很像ruby。我将调用列表中的map,所以第一个倾向是使用respond_to?:map。但是字符串也会响应:map,所以这行不通。 最佳答案 如何将它们全部视为数组?String的行为与仅包含String的Array相同:deffoo(obj,arg)[*arg].eac
我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的
希望我没有误解“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
我有这个: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
我看到有关未找到文件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功能。修复:获取文
我有一个用Rails3编写的站点。我的帖子模型有一个名为“内容”的文本列。在帖子面板中,html表单使用tinymce将“content”列设置为textarea字段。在首页,因为使用了tinymce,post.html.erb的代码需要用这样的原始方法来实现。.好的,现在如果我关闭浏览器javascript,这个文本区域可以在没有tinymce的情况下输入,也许用户会输入任何xss,比如alert('xss');.我的前台会显示那个警告框。我尝试sanitize(@post.content)在posts_controller中,但sanitize方法将相互过滤tinymce样式。例如
出于某种原因,我必须为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#[]=
我是Ruby和Watir-Webdriver的新手。我有一套用VBScript编写的站点自动化程序,我想将其转换为Ruby/Watir,因为我现在必须支持Firefox。我发现我真的很喜欢Ruby,而且我正在研究Watir,但我已经花了一周时间试图让Webdriver显示我的登录屏幕。该站点以带有“我同意”区域的“警告屏幕”开头。用户点击我同意并显示登录屏幕。我需要单击该区域以显示登录屏幕(这是同一页面,实际上是一个表单,只是隐藏了)。我整天都在用VBScript这样做:objExplorer.Document.GetElementsByTagName("area")(0).click
YARD允许我指定方法参数和返回值的类型。因为我真的很喜欢躲避类型,所以很高兴看到YARD还支持通过指定它们必须支持的方法来定义类型。如你所见here,像#first_method,#second_method这样的表达被解释为逻辑析取。这意味着对象需要支持#first_method或#second_method或两者。这不是我需要的。我希望能够指定一个对象需要同时支持我的参数的#first_method和#second_method。有办法指定吗? 最佳答案 没有用于指定复合鸭子类型接口(interface)的惯用语法。也就是说,
🎉精彩专栏推荐💭文末获取联系✍️作者简介:一个热爱把逻辑思维转变为代码的技术博主💂作者主页:【主页——🚀获取更多优质源码】🎓web前端期末大作业:【📚毕设项目精品实战案例(1000套)】🧡程序员有趣的告白方式:【💌HTML七夕情人节表白网页制作(110套)】🌎超炫酷的Echarts大屏可视化源码:【🔰Echarts大屏展示大数据平台可视化(150套)】🔖HTML+CSS+JS实例代码:【🗂️5000套HTML+CSS+JS实例代码(炫酷代码)继续更新中…】🎁免费且实用的WEB前端学习指南:【📂web前端零基础到高级学习视频教程120G干货分享】🥇关于作者:💬历任研发工程师,技术组长,教学总监;