Javascript:访问更高阶函数内的对象范围成员

时间:2012-10-20 10:45:29

标签: javascript oop scope higher-order-functions

域模型

var Question = function(text, answerType){
    this.id = 0
    this.text = text;
}

var Form = function(){
    this.questions = [] 
    this.addQuestion = function(question){
        question.id = this.questions.length + 1
        this.questions.push(question)
    }
}

呈现表单

var FormRenderer = function(){
    this.wrapperSelector = "#wrapper"
    this.render = function(form){
       // how to access renderQuestion member of FormRenderer within the higher-order function?
       $(form.questions).each( function(){ **this.renderQuestion(form, this) }**) 
    }

    this.renderQuestion = function(form, question){
        var questionDomId = "question" + question.id

        var questionText = '<input type="text" size="75" name="questionText" value="'+ question.text +'" /><br/><br/><br/>'
        var questionWrapper  = "<div id='" + questionDomId + "'>" + questionText + "</div>"

        // how do i access wrapperSelector member of FormRender when renderQuestion is called as higher-order function?
        **$(this.wrapperSelector).append(questionWrapper)** 
    }
}

客户端代码

var q1= new Question("question1", "Text Box")
var form = new Form()
form.addQuestion(q1)

var formRenderer = new FormRenderer()
formRenderer.render(form)

问题与标题相同。我已经通过Javascript评论向上面的具体示例请求了帮助。任何帮助表示赞赏。

4 个答案:

答案 0 :(得分:1)

您需要存储对象的引用,如下所示:

var FormRenderer = function(){
    this.wrapperSelector = "#wrapper"
    this.render = function(form){
       $(form.questions).each( this.renderQuestion) ;
    }

   var self = this; // <--------------- 

   this.renderQuestion = function(form, question){
        var questionDomId = "question" + question.id

        var questionText = '<input type="text" size="75" name="questionText" value="'+ question.text +'" /><br/><br/><br/>'
        var questionWrapper  = "<div id='" + questionDomId + "'>" + questionText + "</div>"

        // now use self instead of this
        $(self.wrapperSelector).append(questionWrapper);
    }
}

答案 1 :(得分:0)

您可以在成员函数内的this中获取父对象实例,方法如下所示。

如果object是您的实例,func是一个成员函数,您希望this成为您的实例本身,那么您可以将成员函数调用为:

obj.func.call(obj, <params>);

而不是

object.func(<params>);

在您的情况下,这将是:

var fR = new FormRenderer(<params>);
...
fR.renderQuestion.call(fR, <params>);

您的renderQuestion可以像外面一样使用this。即。

var FormRenderer = function(){
    this.wrapperSelector = "#wrapper"
    ...
    this.renderQuestion = function(form, question){

        // this refers to the object itself, so you can call        
        $(this.wrapperSelector).append(...);
    }
}

答案 2 :(得分:0)

根据Pumbaa80和Bergi的输入,必须进行一些重组以解决问题。谢谢你的回答。

var FormRenderer = function(){
    this.render = function(form){
        var formEventHandler = new FormEventHandler(form)
        $(form.questions).each(new RenderQuestion(formEventHandler).render)
    }

    RenderQuestion = function(formEventHandler){
        this.formEventHandler = formEventHandler
        this.wrapperSelector = "#wrapper"
        var self = this
        this.render = function(index, question){
            var questionDomId = "question" + question.id

            // generate elements
            var questionText = '<input type="text" size="75" name="questionText" value="'+ question.text +'" /><br/>'
            var questionWrapper  = "<div id='" + questionDomId + "'>" + questionText + "</div>"

            // append to dom
            $(self.wrapperSelector).append(questionWrapper)
        }
    }
}

答案 3 :(得分:0)

不要使用jQuery.each - 它会将this引用更改为异常。您可以像这样使用ES 5.1 bind和普通forEach

FormRenderer.prototype.render = function(form) {
    form.questions.forEach(this.renderQuestion.bind(this, form));
};

我建议使用经典的for循环,它比任何更高阶的东西更容易阅读和更快:

FormRenderer.prototype.render = function(form) {
    for (var i=0; i<form.questions.length; i++)
        this.renderQuestion(form, form.questions[i]);
};

如果您真的想要/需要使用jQuery.each,则需要在变量中保留对当前FormRenderer实例(this)的引用:

FormRenderer.prototype.render = function(form) {
    var renderer = this;
    $.each(form.questions, function(i) {
        renderer.renderQuestion(form, this);
    });
};