2010-04-28 73 views
1

在使用JavaScript对象时,我一直在阅读关于'this'关键字的很多文章,但我仍然有些困惑。我很高兴编写面向对象的Javascript,并且通过引用完整的对象路径来解决'this'问题,但我不喜欢这个事实,我仍然觉得'this'混乱。对JavaScript的'this'仍然感到困惑

我找到了一个很好的答案here帮助我,但我仍然不是100%确定。所以,在这个例子上。下面的脚本是从test.html的链接与<script src="js/test.js"></script>

if (!nick) { 
    var nick = {}; 
} 

nick.name= function(){ 
    var helloA = 'Hello A'; 
    console.log('1.',this, this.helloA); 

    var init = function(){ 
     var helloB = 'Hello B'; 
     console.log('2.',this, this.helloB); 
    } 

    return { 
     init: init 
    } 
}(); 

nick.name.init(); 

什么样的期望看到的是

1. Object {} nick.name, 'Hello A' 
2. Object {} init, 'Hello B' 

但是我所得到的是什么?

1. Window test.html, undefined 
2. Object {} init, undefined 

我想我明白了一些什么发生的事情,但如果有人在那里它解释了我,我不会介意。

此外,我不完全确定为什么第一个'console.log'被调用?如果我删除调用init函数//nick.name.init()萤火虫仍然输出1. Window test.html, undefined。这是为什么?为什么在html页面加载时,由窗口对象调用nick.name()?

非常感谢

回答

3

而且,我不完全知道为什么第一“的console.log”被调用呢?

nick.name = function(){ 
    // ... 
}(); 

在这里定义一个函数,立即(因此())调用它,它的返回值({init: init})分配给nick.name

所以执行是:

  1. 创建一个变量nick如果没有一个非虚假值已经
  2. 创建一个匿名函数针对这样...
  3. (因为该函数是在全球范围内为方法执行,而不是window)使用console.logthis在它自己的范围称为helloA
  4. 输出数据的可变含有“1”(原样), ,并且this.helloAwindow.helloA,它不存在。
  5. 定义了一个名为init
  6. 函数会返回一个被分配到nick.name
  7. 然后调用nick.name.init()其执行的name背景下init函数的对象。
  8. 这定义helloB
  9. 然后console.logs “2”(这是),thisname)和this.helloBnick.name.helloB - 这不存在)

所以你得到的第一个输出从console.log('1.',this, this.helloA);

我认为你的主要问题是你很容易混淆this.foo(在调用方法的对象上的属性)与变量作用域(函数可用的变量)

+0

我没有说它在'lowman'的上下文中定义了'helloB'。它在'lowman'的**范围**中定义。存在于给定范围内的变量与对象上的属性不同。 – Quentin 2010-04-28 12:20:54

+0

非常感谢你的帮助David。我已经在早上创造了一些例子,我想我正在慢慢获得它。 – screenm0nkey 2010-04-29 12:04:19

2
  1. this是基于每个功能的基础当函数调用时定义。当你调用一个函数o.f(),this将是o内的函数,并且当你调用它为f(),this将是全局对象(对于浏览器来说,这是窗口)。 您写的nick.name = function(){...}();和右手部分的形式为f(),因此Window

  2. var foo = bar;定义了一个局部变量。它可能不会被作为this.foo访问(当然,除非在全球范围内,但这很愚蠢)。要定义一个成员,你通常会写this.foo = bar;

+0

维克多,这是很好的答案,谢谢。你知道窗口对象为什么叫这个函数吗? – screenm0nkey 2010-04-28 11:39:40

+0

确切地说,当你自己调用一个函数(而不是成员)时,'this'是全局对象,对于Web浏览器来说,它是'Window'。 – 2010-04-28 11:52:30

+0

再次感谢Victor。非常感激。 – screenm0nkey 2010-04-29 12:45:56

2

如果您将this作为函数而不是变量来考虑,这会简单得多。本质上,this是一个返回当前“执行上下文”的函数,也就是当前函数被“应用”到的对象。例如,请考虑以下

function t() { console.log(this)} 

这将返回不同的结果,这取决于你怎么称呼它

t() // print window 

bar = { func: t } 
bar.func() // print bar 

foo = { x: 123 } 
t.apply(foo) // print foo 
+0

美孚在这里不是一个功能,所以它不会有应用方法。我认为你的意思是t.apply(foo)。 apply方法让我们在调用函数时明确地定义执行上下文(this的值)。 (另请参阅Function.call) JavaScript在这种意义上的灵活性可能是一个非常强大的工具,但它也是一个非常令人沮丧的来源,特别是在您开始考虑之前! – adamnfish 2010-04-28 11:31:07

+0

感谢您的答复stereofrog。我可以问一下foo.apply(t)吗?那是一个错误吗?应该是t.apply(foo)//打印foo? 非常感谢 – screenm0nkey 2010-04-28 11:45:05

+0

谢谢stereofrog :) – screenm0nkey 2010-04-29 12:46:53

1

这是你的代码做什么:

  • 它创建一个对象,分配给变量nick
  • 它创建一个匿名函数。
  • 它调用函数(在窗口范围内)。
  • 它将返回值(包含init属性的对象)分配给对象的name属性。
  • 它从init属性(它是一个方法委托)中获取值,并调用该方法。

匿名函数做到这一点:

  • 它声明了一个名为helloA一个局部变量和一个字符串分配给它。 (创建局部变量不会将其作为属性添加到当前对象。)
  • 它记录了this(窗口)和helloA属性(不存在)。
  • 它创建一个匿名函数并分配给本地变量init
  • 它使用属性init和本地变量init创建一个对象。

分配给init属性的匿名函数做到这一点:

  • 它声明了一个名为helloB一个局部变量和一个字符串分配给它。 (创建本地变量不将其添加为属性设置为当前对象。)
  • 它记录this(从name属性,而不是nick变量的对象),并且helloB属性(它不存在) 。
+0

所以我应该使用这个关键字时应用变量对象,即this.helloA或这样做使私人varaibles成为公共? – screenm0nkey 2010-04-28 12:11:35

+0

@Nick:这取决于当前的上下文。如果上下文是一个对象,则可以使用'this'关键字来访问该对象。如果它是默认上下文(窗口),您将为窗口对象添加属性,从而使它们成为全局/公共。 – Guffa 2010-04-28 12:57:37

+0

感谢您的帮助Guffa :) – screenm0nkey 2010-04-29 12:49:27