0

我试图了解 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

4 回答 4

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来确保在 内GetStatethis指向mdl。参考bindhttps ://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind

您原来的 IIFE 实际上是您的绑定实现。问题是 的值this是错误的。目前,每次您需要将模型功能分配给其他功能时,您都需要一直使用bind。您已将您的问题标记为 node.js,bindFunction在 node.js 的原型和任何 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对象。

于 2012-11-28T19:42:35.167 回答
2

当这样定义时:

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

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

如果你这样定义它:

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

机制是一样的,只是this不是。现在它是您执行上述代码的范围的上下文。假设它是在全局范围内完成的——它将是window对象。

于 2012-11-28T19:47:08.877 回答
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用于测试目的。

于 2012-11-28T20:45:03.467 回答
0

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

于 2012-11-28T19:47:09.180 回答