我试图理解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)如果我不能让它与原型一起工作,那是什么这样我才能更好地理解问题的基础。
答案 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
。参考bind
:https://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)
,则会看到相应的m
和o
对象。
答案 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
,因为它支持较旧的浏览器,您可以试试这个:
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
对象。