在JavaScript中,"this"运算符可以在不同的场景下引用不同的东西。
通常在JavaScript"对象"内的方法中,它引用当前对象。
但是当用作回调时,它将成为对调用对象的引用。
我发现这会导致代码出现问题,因为如果你在JavaScript"对象"中使用一个方法作为回调函数,你无法判断"this"是指当前的"对象"还是"this"是指 调用对象。
有人可以澄清如何解决这个问题的用法和最佳实践吗?
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 |    function TestObject() {TestObject.prototype.firstMethod = function(){
 this.callback();
 YAHOO.util.Connect.asyncRequest(method, uri, callBack);
 
 }
 
 TestObject.prototype.callBack = function(o){
 // do something with"this"
 //when method is called directly,"this" resolves to the current object
 //when invoked by the asyncRequest callback,"this" is not the current object
 //what design patterns can make this consistent?
 this.secondMethod();
 }
 TestObject.prototype.secondMethod = function() {
 ;
 }
 }
 | 
关于最佳实践的快速建议,然后我就这个变量的魔法喋喋不休。如果你想在Javascript中使用面向对象编程(OOP)来密切反映更传统/经典的继承模式,那么选择一个框架,学习它的怪癖,不要试图变得聪明。如果你想变得聪明,学习javascript作为一种功能语言,并避免考虑像类这样的事情。
这引出了关于Javascript的最重要的事情之一,并在没有意义时重复自己。 Javascript没有类。如果看起来像一个类,这是一个聪明的把戏。 Javascript有对象(不需要嘲弄引用)和函数。 (这不是100%准确,函数只是对象,但将它们视为单独的东西有时会有所帮助)
此变量附加到函数。无论何时调用函数,都会给出一定的值,具体取决于您调用函数的方式。这通常称为调用模式。
有四种方法可以在javascript中调用函数。您可以将函数作为方法,函数,构造函数和apply来调用。
作为一种方法
方法是附加到对象的函数
| 12
 3
 4
 
 | var foo = {};foo.someMethod = function(){
 alert(this);
 }
 | 
当作为方法调用时,它将绑定到函数/方法所属的对象。在这个例子中,这将绑定到foo。
作为一个功能
如果你有一个独立的函数,这个变量将被绑定到"全局"对象,几乎总是在浏览器的上下文中的窗口对象。
| 12
 3
 4
 
 |  var foo = function(){alert(this);
 }
 foo();
 | 
这可能是你绊倒的,但不要感觉不好。很多人认为这是一个糟糕的设计决定。由于回调是作为函数而不是作为方法调用的,因此您可以看到看似不一致的行为。
很多人通过这样做来解决这个问题
| 12
 3
 4
 5
 6
 7
 
 | var foo = {};foo.someMethod = function (){
 var that=this;
 function bar(){
 alert(that);
 }
 }
 | 
您定义一个指向此的变量。 Closure(一个它自己的主题)保持that,所以如果你把bar称为回调,它仍然有一个引用。
作为构造函数
您还可以将函数作为构造函数调用。根据您正在使用的命名约定(TestObject),这也可能是您正在做的事情,也是您绊倒的原因。
使用new关键字将函数作为构造函数调用。
| 12
 3
 4
 
 | function Foo(){this.confusing = 'hell yeah';
 }
 var myObject = new Foo();
 | 
当作为构造函数调用时,将创建一个新的Object,并将绑定到该对象。同样,如果你有内部函数并且它们被用作回调,你将把它们作为函数调用,并且它将被绑定到全局对象。使用var that = this;技巧/模式。
有些人认为构造函数/ new关键字是Java /传统OOP程序员抛出的骨骼,作为创建类似于类的东西的方法。
使用Apply方法。
最后,每个函数都有一个名为apply的方法(是的,函数是Javascript中的对象)。 Apply允许您确定它的值,并允许您传入一组参数。这是一个无用的例子。
| 12
 3
 4
 5
 6
 7
 
 | function foo(a,b){alert(a);
 alert(b);
 alert(this);
 }
 var args = ['ah','be'];
 foo.apply('omg',args);
 | 
在JavaScript中,this始终引用调用正在执行的函数的对象。因此,如果函数被用作事件处理程序,this将引用触发事件的节点。但如果你有一个对象并在其上调用一个函数,如:
然后myFunction内的this将引用myObject。是否有意义?
要解决它,你需要使用闭包。您可以按如下方式更改代码:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 
 | function TestObject() {TestObject.prototype.firstMethod = function(){
 this.callback();
 YAHOO.util.Connect.asyncRequest(method, uri, callBack);
 }
 
 var that = this;
 TestObject.prototype.callBack = function(o){
 that.secondMethod();
 }
 
 TestObject.prototype.secondMethod = function() {
 ;
 }
 }
 | 
this对应于函数调用的上下文。对于未作为对象一部分调用的函数(无.运算符),这是全局上下文(网页中的window)。对于称为对象方法的函数(通过。运算符),它是对象。
但是,无论你想要什么,你都可以做到。所有函数都有.call()和.apply()方法,可用于使用自定义上下文调用它们。所以,如果我像这样建立一个智利对象:
| 1
 | var Chile = { name: 'booga', stuff: function() { console.log(this.name); } }; | 
...并调用Chile.stuff(),它会产生明显的结果:
但如果我想,我可以采取并真正搞砸它:
| 1
 | Chile.stuff.apply({ name: 'supercalifragilistic' }); | 
这实际上非常有用......
如果您正在使用javascript框架,可能有一个方便的方法来处理这个问题。例如,在Prototype中,您可以调用方法并将其范围限定为特定的"this"对象:
| 12
 
 | var myObject = new TestObject();myObject.firstMethod.bind(myObject);
 | 
注意:bind()返回一个函数,因此您也可以使用它来预先调整类中的回调:
http://www.prototypejs.org/api/function/bind
如果你正在使用Prototype,你可以使用bind()和bindAsEventListener()来解决这个问题。
你也可以使用Function.Apply(thisArg,argsArray)...其中thisArg确定函数内部的值...第二个参数是一个可选的arguments数组,你也可以传递给你的函数。
如果您不打算使用第二个参数,请不要传递任何内容。如果将null(或任何非数组)传递给function.apply()的第二个参数,Internet Explorer将抛出一个TypeError ...
使用示例代码,它看起来像:
| 1
 | YAHOO.util.Connect.asyncRequest(method, uri, callBack.Apply(this)); | 
一旦从其他上下文调用回调方法,我通常会使用我称之为回调上下文的东西:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 
 | var ctx = function CallbackContext(){
 _callbackSender
 ...
 }
 
 function DoCallback(_sender, delegate, callbackFunc)
 {
 ctx = _callbackSender = _sender;
 delegate();
 }
 
 function TestObject()
 {
 test = function()
 {
 DoCallback(otherFunc, callbackHandler);
 }
 
 callbackHandler = function()
 {
 ctx._callbackSender;
 //or this = ctx._callbacjHandler;
 }
 }
 | 
我相信这可能是由于[闭包]的想法(http://en.wikipedia.org/wiki/Closure_(computer_science)如何在Javascript中工作。
我自己就是要掌握封口。阅读链接的维基百科文章。
这是另一篇有更多信息的文章。
那里的任何人都能证实这一点吗?