7

我可以说,对于那些来自像C#这样的语言的人来说,“this”关键字是Javascript中最令人困惑的部分。

我在互联网和StackOverflow上也读过很多关于这方面的内容。喜欢在这里在这里.

我知道“this”关键字将绑定到上下文。在构造函数中,它将被绑定到正在创建的对象,当没有即时上下文时,它将绑定到全局对象(即窗口)

我知道这一切,但困惑仍未完全消除;所以最好的理解方法是测试代码。


所以我决定写一些小代码,我惊讶于关键字。

下面是我测试的代码:

函数sayHi(名称){var tt=名称;返回{ss:tt,测试,work:函数(anotherName){警报(“hiiii”+另一个名称);}};}//这个方法调用现在没有任何效果sayHi(“约翰”);var hi2=新sayHi(“华莱士”);hi2.工作(“五月”);警报(hi2.ss);

如预期,警报窗口将显示(5月8日),然后显示(华莱士)。现在请注意,该行sayHi(“约翰”);根本没有效果。

现在,当我只更改一件事(更改var tt=>this.tt)时,就会出现混乱:

函数sayHi(名称){//这是我唯一做的改变。this.tt=名称;返回{ss:tt,测试,work:函数(anotherName){警报(“hiiii”+另一个名称);}};}//现在这个行调用将有问题sayHi(“约翰”);var hi2=新sayHi(“华莱士”);hi2.工作(“五月”);警报(hi2.ss);

结果让我惊讶的是,当警报发出时(Hiiiiiii May),然后(John)没有(wallace);

所以我有了评论这句话的想法sayHi(“约翰”);但这导致整个代码无法正常工作。

这个演示在这里

我知道这可能是个新问题。但这真的很令人困惑,我确实试着阅读了许多文章和SO问题,但我忽略了这一点。

为什么这条线sayHi(“约翰”);将hi2.ss设置为John??以及为什么当我们删除它时,它会破坏代码;尽管我们调用问好方法,使用新的关键词之后??

  • 在“严格”模式下,未定义在没有任何上下文的情况下调用函数时。
    – 波蒂
    评论 2014年5月30日13:16
  • ss:tt,测试,是基于一个局部变量进行赋值的,而不是它的属性,因为变量不存在,所以应该是未定义的。 评论 2014年5月30日13:17
  • @把答案读下来,然后把它们全部理解。现在你的评论有意义了。谢天谢地 评论 2014年5月30日13:39

3个答案

重置为默认值
6

因为您将参数“name”指定给(在这种情况下窗口),您随后在该对象文本中对“tt”的引用将指向全局对象的“tt”属性,因为这是下一个封闭范围。

您第一次拨打“sayHi”时没有新的接线员,所以在那个通话中将引用全局对象(窗口). 第二版本中的第一行

this.tt=名称;

因此将设置窗口.tt“约翰”。

下一个调用是使用新的操作员。正因为如此,在函数中指的是新的实例化对象。这条线

this.tt=名称;

因此对任何事情都没有任何影响,因为该函数返回一个不同的对象。测试的最后一行:

警报(hi2.ss);

说“约翰”是因为这就是窗口.tt为什么这很重要?因为“sayHi”返回一个对象,其属性(“ss”)由符号“tt”的值设置。范围内唯一的“tt”是窗口.tt,在第一调用函数。

4
  • 谢谢你的回答。。但我仍然感到困惑。所以你说当我调用sayHi(“john”)时,“this”是(窗口),然后是window.tt=john。。。但为什么当我用创建的新对象(hi2)再次调用该方法时,hi2.tt仍然是john而不是wallace??我仍然困惑。。欣赏进一步的说明 评论 2014年5月30日13:23
  • 是“约翰”,因为在第二次通话中, 窗口-你称之为新的.
    – 波蒂
    评论 2014年5月30日13:24
  • 非常清楚。感谢您的耐心,但现在我的问题如下:第一次打电话给sayHi(“john”)给了我一个变量(window.tt=“johan”);但第二个调用(hi2=new sayHi(“wallace”)应该会给我另一个变量(hi2.tt=“wallase”)。。你是说,由于tt是在全球范围内建立的,所以不允许在本地使用它吗?? 评论 2014年5月30日13:30
  • 不,不是高2.tt-它是由于您通过调用函数而创建的全新对象新的。函数的第一行将成功地将该对象的“tt”属性设置为“wallace”,但随后将“ss”设置为纯“tt”,而不是“this.tt”。
    – 尖尖的
    评论 2014年5月30日13:51

当您第一次调用sayHi(“约翰”);,将指向全局对象窗口.这意味着this.tt=名称实际上创建了一个全局tt公司变量。

然后当你调用new sayHi(“华莱士”);,正确指向的新实例问好,但您正在返回另一个对象,而不是让新的自然返回实例。

如果你仔细观察你的对象文字,你可以定义不锈钢喜欢ss:tt,测试,。因为您没有使用这个.tt而且没有tt公司符号,则该值将被解析为全局变量(之前设置为约翰).

4
  • 我爱你。。尽管这里的所有答案都是信息性的;但是你提醒我注意我所犯的对象文字错误。当我定义ss:tt(秒:tt)ss:这个.tt代码的行为符合预期。。。现在我明白了。 评论 2014年5月30日13:37
  • 我可以编辑你的答案,以便以正确的格式添加代码吗? 评论 2014年5月30日13:40
  • @stackunderflow我很高兴能帮上忙。附加到的实例变量和用声明的函数范围变量无功功率,无功功率是两个截然不同的东西。自行访问变量,例如。某些变量而不是此.someVar对象对象变量永远不会解析为对象成员(作为属性的全局变量除外窗口在浏览器中)。
    – 格子布
    评论 2014年5月30日13:45
  • 1
    @stackunderflow通常修改答案的内容不是一种公认的做法,除非你不改变它的含义。这通常意味着除了纠正语法错误或打字错误之外,你不能做更多的事情。答案的创建者并不是编辑审批流程中唯一涉及的人,您的编辑很可能会被即将参与此对话的人拒绝。通常最好留下评论,让答案的所有者处理。
    – 格子布
    评论 2014年5月30日13:50

调用构造函数时,如果函数中不存在返回语句,则隐式返回,否则返回返回值被忽略了。

在第二个示例中,您将name参数另存为这个.tt但是返回不同的对象。这就是为什么事情没有进展。基本使用或返回自定义对象,但不要同时执行这两项操作。

2
  • 1
    这不是真正的问题。我认为OP很清楚,他正在凌驾于隐含回报之上。OP的困惑更多是关于为什么ss:tt(秒:tt)并没有达到他的期望。
    – 格子布
    评论 2014年5月30日13:39
  • @plalx:我的答案解释原因ss:tt(秒:tt)并没有达到他的期望。 评论 2014年5月30日14:34

你的答案

单击“发布您的答案”,表示您同意我们的服务条款并确认您已阅读我们的隐私政策.

不是你想要的答案吗?浏览标记的其他问题问你自己的问题.