如何在javascript中正确地将函数传递给其他函数

时间:2012-11-28 19:39:31

标签: javascript node.js

我试图理解javascript传递函数的方式,并且有一个问题,为什么原型函数不能访问函数构造函数中定义的var,而构造函数中定义的函数可以访问var。这是有效的代码:

   var model = function model() {
       this.state = 1;
       this.GetState =   (function(scope){
           return function(){ return scope.state;};
       })(this);
   }

    var othermodel = function othermodel(mdl) {
        this.GetStateFn = mdl.GetState;
    }

    othermodel.prototype.WriteState = function() {
        console.log(this.GetStateFn.call());
    };

    var m = new model();
    var o = new othermodel(m)


    o.WriteState();

这有效并且有意义 - GetState()函数可以访问this.state。

但是,如果我按如下方式创建GetState:

 model.prototype.GetState =   (function(scope){
        return function(){ return scope.state;};
    })(this);

结果将是未定义范围的错误。

我更喜欢使用原型方法,因为我不想在任何模型中使用该函数的副本,但似乎原型无法工作,因为它无法访问模型的特定实例

所以,有人能给我一个很好的解释a)我需要做些什么才能让它与原型一起工作(假设我可以)和b)如果我不能让它与原型一起工作,那是什么这样我才能更好地理解问题的基础。

4 个答案:

答案 0 :(得分:2)

为什么不简单地以这种方式编写函数

model.prototype.GetState = function() { return this.state; }

var othermodel = function othermodel(mdl) {
    this.GetStateFn = mdl.GetState.bind(mdl);
}

othermodel.prototype.WriteState = function() {
    console.log(this.GetStateFn.call());
};

上面的代码可以使用,因为在大多数情况下,您将执行m.GetState()之类的代码。这是一个调用函数作为对象方法的示例。在这种情况下,this保证指向对象m。你似乎知道原型链是如何工作的,所以我不会去那里。

在将函数引用分配给其他模型时,我们使用.bind确保在GetState内,this指向mdl。参考bindhttps://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind

您原来的IIFE实际上是您对bind的实现。问题是this的价值是错误的。目前,每次需要将模型功能分配给其他功能时,您需要在所有这些时间使用bind。您已将问题标记为node.js,bind可在node.js中的Function原型和任何与ES5兼容的浏览器上使用。如果您需要在较旧的浏览器或不支持bind的环境中运行上述代码,请将bind替换为您的IIFE。

至于你的代码无效的原因,

model.prototype.GetState =   (function(scope){
    return function(){ return scope.state;};
})(this);

此处,this未引用最终模型对象(m)。 this可以引用javascript中的5个选项中的任何一个。请参阅:https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/this

让我们假设上面的代码在一些脚本标记内的html文件中。然后this将引用窗口对象。 window没有任何名为state的属性,因此undefined。如果您在脚本末尾console.log(this.m, this.o),则会看到相应的mo对象。

答案 1 :(得分:2)

如下定义:

var model = function model() {
    this.state = 1;
    this.GetState =   (function(scope){
        return function(){ return scope.state;};
    })(this);
}

声明匿名函数并立即执行。 this作为参数传递给该自执行函数。因此 - 返回一个新函数,但此函数在其闭包中具有scope参数 - 以便在作用域退出后可以访问它。因此,该函数在被调用时仍然可以访问“封闭”state的{​​{1}}属性(成为this且已关闭的属性)。

如果你这样定义:

scope

机制是相同的,只是model.prototype.GetState = (function(scope){ return function(){ return scope.state;}; })(this); 不是。它现在是您执行上述代码的范围的上下文。假设它在全局范围内完成 - 它将是this对象。

答案 2 :(得分:1)

如果您不想使用bind,因为它支持较旧的浏览器,您可以试试这个:

http://jsfiddle.net/j7h97/1/

var model = function (state) {
    this.state = state || new Date().getTime();
};

model.prototype.GetState = function () {
    return this.state;
};

model.prototype.WriteState = function () {
    console.log("model WriteState: " + this.GetState());
};

var othermodel = function othermodel (mdl) {
    this.GetStateFn = function () {
        return mdl.GetState.call(mdl);
    };
};

othermodel.prototype.WriteState = function () {
    console.log("othermodel WriteState: " + this.GetStateFn());
};

var model1 = new model();
model1.WriteState();
var othermodel1 = new othermodel(model1);
othermodel1.WriteState();

var model2 = new model();
model2.WriteState();
var othermodel2 = new othermodel(model2);
othermodel2.WriteState();

似乎在没有bind的情况下做你想做的事。我出于测试目的创建了model.prototype.WriteState

答案 3 :(得分:0)

取决于它的调用位置。如果它在全局范围内,this将不会引用该模型。如果它在浏览器中运行,它将引用全局window对象。