关于Javascript中'this'关键字的混淆

时间:2014-05-30 13:12:52

标签: javascript this

对于那些来自C#等语言的人,我可以声称'this'关键字是Javascript中最令人困惑的部分。

我已经在互联网和StackOverflow上阅读了很多相关内容。例如herehere

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

我知道这一切,但是混乱还没有完全清除;因此,最好的理解方法是测试代码。


所以我决定编写一些小代码,我对this关键字的复杂程度感到惊讶。

这是我测试的代码:

 function sayHi(name){
   var tt = name;
   return {
     ss: tt,
     work: function(anotherName){

     alert ("hiiiii    " + anotherName);
   }
 };
}

//this method invocation has no effect at all right now
sayHi("John");


var hi2 = new sayHi("wallace");

hi2.work("May");
alert(hi2.ss);

正如预期的那样,警报窗口将显示(Hiiiiii May)然后(华莱士)。现在请注意,sayHi("John");行根本没有效果。

现在只有改变一件事时才会开始混淆(改变var tt => this.tt):

 function sayHi(name){
   //this is the ONLY change I did.
   this.tt = name;
   return {
     ss: tt,
     work: function(anotherName){

     alert ("hiiiii    " + anotherName);
   }
 };
}

// Now this line invocation will be problematic 
sayHi("John");


var hi2 = new sayHi("wallace");

hi2.work("May");
alert(hi2.ss);
当警报方法(Hiiiiiii May)和(John)没有(华莱士)时,结果让我感到惊讶;

所以我有想法对sayHi("John");行进行评论,但这导致整个代码无法正常运行。

demo is here

我知道这可能是一个新问题。但这里真的很混乱,我确实尝试阅读很多文章和SO问题,但我忽略了这一点。

为什么行sayHi("John");将hi2.ss设置为John?为什么在删除代码时会破坏代码;虽然我们之后使用sayHi关键字调用new方法?

3 个答案:

答案 0 :(得分:6)

因为您指定了参数" name"对于this引用的对象的属性(在本例中为window),您随后引用" tt"在那个对象文字中将是" tt"全局对象的属性,因为它是下一个封闭范围。

你第一次打电话给" sayHi"在没有new运算符的情况下生成,因此调用this将引用全局对象(window)。第二个版本中的第一行

this.tt = name;

因此会将window.tt设置为" John"。

下一次调用是使用new运算符进行的。因此,函数中的this引用了新实例化的对象。这条线

this.tt = name;
因此,

对任何事物都没有任何净影响,因为该函数在所有情况下都会返回不同的对象。测试的最后一行:

alert(hi2.ss);

约翰"因为那是window.tt中的内容。为什么这么重要?因为" sayHi"返回一个对象,该对象具有从符号" tt"的值设置的属性(" ss")。唯一的" tt"在范围内将window.tt,这是在第一次调用函数时设置的。

答案 1 :(得分:3)

当调用构造函数时,如果函数中不存在return语句,则隐式返回this,否则返回返回值,并忽略this

在第二个示例中,您将name参数保存为this.tt,但返回另一个对象。这就是事情不起作用的原因。基本上使用this或返回自定义对象,但不要同时执行这两项操作。

答案 2 :(得分:3)

首次调用sayHi("John");时,this将指向全局对象window。这意味着this.tt = name实际上会创建一个全局tt变量。

然后,当您调用new sayHi("wallace");时,this正确指向sayHi的新实例,但您要返回另一个对象,而不是让new自然返回实例。

如果仔细查看对象字面值,请将ss定义为ss: tt,。由于您没有使用this.tt并且在构造函数的作用域中找不到tt符号,因此该值将被解析为全局变量(之前已设置为John)。