这(下面)最终给出了“超出最大调用堆栈大小”错误。看起来这是由于“this.actions”对象中“this”的解释方式。在该对象中,“this”是指那个对象,还是Unit类的实例?如果是前者,将.bind(this)放在“this.actions”对象的末尾,使“this”引用类实例代替?如果是这样,为什么?如果没有,为什么不呢?
function Unit(){
this.move = function(direction){
switch(direction){
case 'up': { console.log('foo'); break; }
case 'down': { console.log('foooo'); break; }
}
console.log('bar');
}
this.shoot = function(){console.log('zap')}
this.actions = {
'moveUp' : function(){ this.move('up') },
'moveDown' : function(){ this.move('down') },
'shoot' : function(){ this.shoot() }
}
return this
}
答案 0 :(得分:2)
使用bind
原因:
让我们说:
var r = new Unit();
当你拨打r.actions.moveup()时,这个'传递函数中传递的是动作。
function Unit(){
this.move = function(direction){
switch(direction){
case 'up': { console.log('foo'); break; }
case 'down': { console.log('foooo'); break; }
}
console.log('bar');
}
this.shoot = function(){console.log('zap')}
this.actions = {
'moveUp' : function(){ this.move('up') }.bind(this),
'moveDown' : function(){ this.move('down') }.bind(this),
'shoot' : function(){ this.shoot() }.bind(this)
}
return this
}
答案 1 :(得分:2)
this
对象中的关键字actions
将引用actions
对象。
一些可能的修复可能如下所示:
function Unit(){
var self = this;
this.move = function(direction){
switch(direction){
case 'up': { console.log('foo'); break; }
case 'down': { console.log('foooo'); break; }
}
console.log('bar');
}
this.shoot = function(){console.log('zap')}
this.actions = {
'moveUp' : function(){ this.move('up') }.bind(self),
'moveDown' : function(){ this.move('down') }.bind(self),
'shoot' : function(){ this.shoot() }.bind(self)
}
return this
}
或者,当您调用这些方法时,可以使用call
或apply
例如:
var coolUnit = new Unit();
Unit.actions.moveUp.call(coolUnit);
在对象的上下文中理解this
需要一些工作,但这里有一些资源:
How does the "this" keyword work?
http://unschooled.org/2012/03/understanding-javascript-this/
http://javascriptissexy.com/understand-javascripts-this-with-clarity-and-master-it/
TL; DR - 有一系列心理规则"您可以使用它来帮助跟踪给定上下文中this
的内容。例如。 左边的规则,其中"点"左边的对象得到this
绑定。
Object.foo() <- `this` in the method `foo` will point to `Object`
使用&#34;规则&#34;如上所述,您可以合理化new Unit.actions.moveUp()
将this
绑定集设置为指向actions对象,因为它的是左边的。
或者您可以使用call
/ bind
/ apply
将this
绑定到您希望的上下文,如上所示。
答案 2 :(得分:1)
另一种解决方案:this
不是变量。嵌套函数可以访问“父”函数(clousure)中定义的所有变量 - 您可以创建变量,为其分配this
,并使用它而不是this
,它会做你做的事情想要和期待:
function Unit(){
var self = this;
self.move = function(direction){
switch(direction){
case 'up': { console.log('foo'); break; }
case 'down': { console.log('foooo'); break; }
}
console.log('bar');
}
self.shoot = function(){console.log('zap')}
self.actions = {
'moveUp' : function(){ self.move('up') },
'moveDown' : function(){ self.move('down') },
'shoot' : function(){ self.shoot() }
}
return self
}
答案 3 :(得分:0)
最近我遇到了关于此问题的this article。
在4.2节中,他使用了一个类似于你的代码的例子,突出了遗忘&#39; new&#39;的缺陷。 &#39;这&#39;在函数调用中指向全局对象(窗口或浏览器),因此当您返回它时,将函数放在全局对象上,然后返回对它的引用。如果您使用了新的Unit()并且没有返回它,那么您将得到一个包含您的函数的对象。
你可以使用bind,但我认为它会像Unit.bind(Unit)那样看起来很奇怪。
您也可以使用工厂功能返回对象,您不必担心忘记新的
function Unit(){
var move = function(direction){
switch(direction){
case 'up': { console.log('foo'); break; }
case 'down': { console.log('foooo'); break; }
}
console.log('bar');
};
var shoot = function(){console.log('zap')};
var actions = {
moveUp : function(){ move('up') },
moveDown : function(){ move('down') },
shoot : shoot
};
return {
actions:actions
};
}
var player1=Unit();
player1.actions.shoot();
player1.actions.moveDown();
player1.actions.moveUp();
我从调用移动中移除了这个,部分问题是动作是一个对象而不是一个函数,所以虽然你可以在对象内部的函数上使用bind,你可以像我在代码中那样关闭在函数上然后公开它。
此外,如果您使用self = this并且不使用new关键字,您仍然可以引用窗口/浏览器对象并创建全局范围。