在Javascript中,为什么;这";操作员不一致?
在JavaScript中,“this”操作符可以在不同的场景下引用不同的内容 通常在JavaScript“对象”中的方法中,它引用当前对象 但当用作回调时,它将成为对调用对象的引用 我发现这会导致代码中出现问题,因为如果使用JavaScript“对象”中的方法作为回调函数,则无法判断“this”是指当前的“对象”还是“this”指调用对象 有人能澄清如何绕过这个问题的用法和最佳实践吗在Javascript中,为什么;这";操作员不一致?,javascript,Javascript,在JavaScript中,“this”操作符可以在不同的场景下引用不同的内容 通常在JavaScript“对象”中的方法中,它引用当前对象 但当用作回调时,它将成为对调用对象的引用 我发现这会导致代码中出现问题,因为如果使用JavaScript“对象”中的方法作为回调函数,则无法判断“this”是指当前的“对象”还是“this”指调用对象 有人能澄清如何绕过这个问题的用法和最佳实践吗 function TestObject() { TestObject.protot
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() {
alert('test');
}
}
我相信这可能是由于[closures](闭包)的思想是如何在Javascript中工作的 我自己刚刚开始处理闭包问题。请阅读维基百科的链接文章 这里有更多的信息
有没有人能够确认这一点?一旦从其他上下文调用回调方法,我通常会使用我称之为回调上下文的东西:
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;
}
}
在JavaScript中,
此
始终指调用正在执行的函数的对象。因此,如果函数用作事件处理程序,此
将指触发事件的节点。但是如果您有一个对象并在其上调用函数,如:
myObject.myFunction();
然后这个内部的myFunction
将引用myObject
。它有意义吗
要绕过它,您需要使用闭包。您可以按如下方式更改代码:
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() {
alert('test');
}
}
此
对应于函数调用的上下文。对于未作为对象一部分调用的函数(无
运算符),这是全局上下文(网页中的窗口
)。对于作为对象方法调用的函数(通过.operator),这是对象
但是,您可以随意设置。所有函数都有.call()和.apply()方法,可用于通过自定义上下文调用它们。因此,如果我像这样设置对象:
var Chile = { name: 'booga', stuff: function() { console.log(this.name); } };
…并调用Chile.stuff(),它将产生明显的结果:
booga
但如果我愿意,我可以拿着它真的去搞砸它:
这实际上非常有用…您也可以使用Function.Apply(thisArg,argsArray)…其中thisArg确定函数中此参数的值…第二个参数是可选参数数组,您也可以将其传递给函数
如果不打算使用第二个参数,请不要向其传递任何内容。如果将null(或任何非数组的内容)传递给function.apply()的第二个参数,Internet Explorer将向您抛出TypeError
根据您给出的示例代码,它看起来像:
YAHOO.util.Connect.asyncRequest(method, uri, callBack.Apply(this));
在我喋喋不休地谈论这个变量的神奇之处之前,快速给出最佳实践的建议。如果你想要面向对象编程(OOP)在与更传统/经典的继承模式密切相关的Javascript中,选择一个框架,学习它的怪癖,不要试图变得聪明。如果你想变得聪明,请将Javascript作为一种函数语言学习,并避免考虑类之类的事情
这就引出了关于Javascript的最重要的一点,当它没有意义时,请您自己重复。Javascript没有类。如果某个东西看起来像类,这是一个聪明的把戏。Javascript有对象(无需使用嘲讽性引号)和函数。(这并不是100%准确,函数只是对象,但有时将它们视为独立的东西会有所帮助)
此变量附加到函数。无论何时调用函数,都会根据调用函数的方式为其指定特定值。这通常称为调用模式
javascript中有四种调用函数的方法。您可以将函数作为方法、函数、构造函数和应用程序调用
作为一种方法
方法是附加到对象的函数
var foo = {};
foo.someMethod = function(){
alert(this);
}
当作为方法调用时,它将绑定到函数/方法所属的对象。在本例中,它将绑定到foo
作为一项功能
如果您有一个独立函数,此变量将绑定到“全局”对象,几乎总是浏览器上下文中的窗口对象
var foo = function(){
alert(this);
}
foo();
<强>这可能是绊倒你的“<强”,但不要感觉不好。很多人认为这是一个糟糕的设计决定。因为回调被调用为函数而不是方法,这就是为什么你看到什么是不一致的行为。
很多人通过这样做来回避这个问题
var foo = {};
foo.someMethod = function (){
var that=this;
function bar(){
alert(that);
}
}
您定义了一个指向此的变量。闭包(它自己的一个主题)将保持在周围,所以如果您将bar作为回调调用,它仍然有一个引用
作为构造器
您还可以将函数作为构造函数调用。根据您正在使用的命名约定(TestObject
),这也可能是您正在做的事情,也可能是让您绊倒的事情
使用new
关键字将函数作为构造函数调用
function Foo(){
this.confusing = 'hell yeah';
}
var myObject = new Foo();
当作为构造函数调用时,将创建一个新对象,该对象将绑定到该对象。同样,如果您有内部函数,并且它们被用作回调,则您将作为函数调用它们,并且这将绑定到全局对象。使用该var that=this;
trick/pattern
有些人认为constructor/new关键字是Java/传统OOP程序员用来创建类似类的东西的一块骨头
使用Apply方法。
最后,每个函数都有一个名为apply
的方法(是的,函数是Javascript中的对象)。apply允许您确定该方法的值,还允许您传入一个参数数组。下面是一个无用的示例
function foo(a,b){
alert(a);
alert(b);
alert(this);
}
var args = ['ah','be'];
foo.apply('omg',args);
如果您使用的是Prototype,那么您可以使用并绕过该问题。如果您使用的是jav
function foo(a,b){
alert(a);
alert(b);
alert(this);
}
var args = ['ah','be'];
foo.apply('omg',args);
var myObject = new TestObject();
myObject.firstMethod.bind(myObject);
callBack.bind(this);