【问题标题】:How to inherit from this javascript function如何继承这个javascript函数
【发布时间】:2014-01-03 18:58:11
【问题描述】:

我试图更好地理解 javascript 中的继承。我的目标是编写一个函数来声明一些变量并设置一个环境,以便其他函数可以基于它构建。我有点像 Ruby 中的 mixins 思路。这是一个不起作用的简单示例。

function baseFunction(){

  this.my_var = "hello world";

};

function speakMessage(){

  alert(this.my_var);

}

speakMessage.prototype = baseFunction();

speakmessage();

我想如果我将原型设置为 baseFunction,那么将在 baseFunction 中搜索任何在 speakMessage 函数中找不到的属性。这不对吗?我该如何让它发挥作用?

【问题讨论】:

  • 你知道什么是闭包吗?
  • 这段代码并没有像你想象的那样做。当您调用baseFunction() 时,this 实际上将是window!您需要使用new 关键字。 speakMessage.prototype = new baseFunction();,然后是new speakMessage();
  • 这是一个有趣的主题,原型的组合。我习惯于使用 new .... 有人知道我可以在哪里进一步了解它吗?
  • 下面的答案可以帮助你理解如何使用构造函数创建实例,以及一个构造函数如何通过原型和调用Parent.apply(this,arguments);stackoverflow.com/a/16063711/1641941从另一个构造函数继承
  • @NetaMeta 你是对的,如果你想用speakMessage继承baseFunction,你应该使用new。当前将 speakMessage.prototype 设置为 baseFunction (=undefined) 的结果将设置 window.my_var (因为调用 baseFunction 时使用 window 作为调用对象),稍后会发出警报“Hello World”,因为 speakMessage 是使用 window 作为调用对象调用的。与从 baseFunction 继承任何内容的 speakMessage 无关。

标签: javascript


【解决方案1】:

简单的答案,但是...speakMessage();(大 M):-)

Javascript 区分大小写。

我错过了 HMR 的精彩评论:如果在 Javascript 中与 new 一起使用,函数就像构造函数一样。请注意我添加到您的代码中的两个new

my_var = "goodbye world";

function baseFunction() {
  this.my_var = "hello world";
}

function speakMessage() {
  alert(this.my_var);
}

speakMessage.prototype = new baseFunction(); // new: inherit from object
new speakMessage(); // object constructor: hello world
speakMessage(); // function: goodbye world from window object context

也看看 HMR 的回答。

【讨论】:

  • @asolberg 确切地说:-) 让我的回答不那么简短,您可以查看bind(),它可以让您使用this。还可以查看apply() 并调用函数。
  • 谢谢!感谢您的帮助。
  • 唯一有效的原因是this 是窗口并且将 speakMessage.prototype 设置为未定义(因为 baseFunction 不返回任何内容)不会使 speakMessage 继承任何内容。它所做的只是设置 window.my_var 并稍后提醒它,因为 speakMessage 是用window 作为调用对象来调用的。与从 baseFunction 继承任何内容的 speakMessage 无关。
  • @HMR:我错过了,很棒的评论!我更新了我的答案以阐明上下文是如何工作的,并赞成您的答案以进一步澄清它。
  • @HMR - 谢谢。我现在明白了很多。起初我是从错误的角度接近 Ruby 风格的函数“混合”,但我现在看到 Javascript 是原型,只有通过设置原型才能塑造原型链,然后确定你的继承层次。
【解决方案2】:

小错误。你调用了 speakmessage();当您创建函数 speakMessage(){}

这应该可以解决它。

function baseFunction(){

  this.my_var = "hello world";

};

function speakMessage(){

  alert(this.my_var);

}

speakMessage.prototype = baseFunction();

speakMessage();

【讨论】:

  • 它提供预期输出的事实并不能使它工作。问题建议OP想要继承。我猜 speakMessage 应该继承自 baseFunction。
【解决方案3】:

对于未来的绊脚石;之前给出的答案仅解决了OP问题中的错字。至于从 baseFunction 继承的 speakMessage,OP 的代码是完全错误的,应该/可能看起来像这样:

(注意构造函数应该以大写字母开头)

function BaseFunction(args){
  //name is instance specific
  //defaults to World
  this.name = (args&&args.name)?args.name:"World";
};
//shared members 
BaseFunction.prototype.saySomething=function(){
  return "From BaseFunction:"+this.name;
};

function SpeakMessage(args){
  //re use BaseFunction constructor code
  BaseFunction.call(this,args);
}
//inherit shared members from prototype
SpeakMessage.prototype = Object.create(BaseFunction.prototype);
//repair built in constructor value (or it'll point to BaseFunction)
SpeakMessage.prototype.constructor=SpeakMessage;
//extend saySomething, this is optional an shows how
// to add extra functionality to existing Parent functions
SpeakMessage.prototype.saySomething=function(){
  return BaseFunction.prototype.saySomething.call(this) + 
    ", from SpeakMessage:"+this.name;
};

var world = new SpeakMessage();//defaults name to be "world"
//following will output: From BaseFunction:World, from SpeakMessage:World
console.log(world.saySomething());
var op = new SpeakMessage({name:"OP"});
//following will output:From BaseFunction:OP, from SpeakMessage:OP
console.log(op.saySomething());
var parent = new BaseFunction();
console.log(parent.saySomething());//=From BaseFunction:World

与 cmets 一样;有关构造函数和原型的更多信息:https://stackoverflow.com/a/16063711/1641941

至于提到闭包的评论;对于更简单的对象,您可以使用闭包而不是构造函数:

var baseFunction=function(message){
  return function(){
    console.log("Hello "+message);
  };
}

var world = baseFunction("World");
var op = baseFunction("OP");
world();//=Hello World
op();//=Hello OP

更多关于关闭的信息:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures

【讨论】:

  • 如果您不使用属性,是否可以只使用new 而不是Object.create,或者还有其他区别吗?看看你的SpeakMessage.prototype.constructor=SpeakMessage; - 我相信父母不应该知道他的孩子设计得很好,尽管 Javascript 可以做到。
  • @JanTuroň构造函数是JS自带的prototype属性。 var t=function();t.prototype.constructor===t;//true 但是因为你设置了SomeConstructor.prototype=somethingElse 你覆盖了那个值,这就是你修复它的原因。父母不知道它是孩子,但孩子知道它是父母。为了更容易重构,您可以使用辅助函数来设置它。我将在这个答案stackoverflow.com/a/16063711/1641941 中添加一些关于随之而来的棘手问题。
  • @JanTuroň 至于使用 new,这不是一个好主意,因为 Parent 可能有实例特定成员被放在 Child 的原型上而没有用(最好的情况是当你做 Parent.call(this ) 在子体中) stackoverflow.com/q/20915711/1641941。另一个原因是 Parent 可能有一些不需要或无法调用的耗时和资源消耗代码(如果不使您的代码不必要地复杂化,则无法解决某些检查)。如果 Parent 的 body 是空的,我猜你可以使用它,但是当你重构 Parent 代码时可能需要重新做
  • 哇!您在评论中的那个答案中写了一本书!我敢打赌这不是你第一次看到 Javascript :-) 干得好。
  • @JanTuroň 谢谢,我觉得很有帮助,希望 12 年前就在那里。当我试图弄清楚某些事情时,我最终将其写为答案,并希望其他人能够改进、纠正或更新它。
猜你喜欢
  • 1970-01-01
  • 2011-11-24
  • 1970-01-01
  • 1970-01-01
  • 2015-06-18
  • 2013-09-17
  • 1970-01-01
  • 2014-02-25
  • 1970-01-01
相关资源
最近更新 更多